JUnit4入门 Mockito单元测试示列

JUnit4入门

JUnit注解

在这里插入图片描述

JUnit断言

在这里插入图片描述

示列一

package com.xsz;

import org.junit.Assert;
import org.junit.Test;

/**
 * assertEquals() 如果比较的两个对象是相等的,此方法将正常返回;否则失败显示在JUnit的窗口测试将中止。
 * assertSame() 和 assertNotSame() 方法测试两个对象引用指向完全相同的对象。
 * assertNull() 和 assertNotNull() 方法测试一个变量是否为空或不为空(null)。
 * assertTrue() 和 assertFalse() 方法测试if条件或变量是true还是false。
 * assertArrayEquals() 将比较两个数组,如果它们相等,则该方法将继续进行不会发出错误。否则失败将显示在JUnit窗口和中止测试。
 * ————————————————
 */
public class AssertionTest {
    @Test
    public void test() {
        String obj1 = "junit";
        String obj2 = "junit";
        String obj3 = "test";
        String obj4 = "test";
        String obj5 = null;

        int var1 = 1;
        int var2 = 2;

        int[] array1 = {1, 2, 3};
        int[] array2 = {1, 2, 3};

        Assert.assertEquals(obj1, obj2);

        Assert.assertSame(obj3, obj4);
        Assert.assertNotSame(obj2, obj4);

        Assert.assertNotNull(obj1);
        Assert.assertNull(obj5);

        Assert.assertTrue(var1 < var2);
        Assert.assertFalse(var1 > var2);

        Assert.assertArrayEquals(array1, array2);

    }

}

示列二

package com.xsz;


import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;
import java.util.Collection;

/**
 * 步骤一: 指定定参数运行器
 */
@RunWith(Parameterized.class)
public class PrimeNumberCheckerTest {

    /**
     * 步骤二:声明变量
     */
    private Integer inputNumber;
    private Boolean expectedResult;
    private PrimeNumberChecker primeNumberChecker;

    /**
     * 步骤三:为测试类声明一个带有参数的公共构造函数,为变量赋值
     */
    public PrimeNumberCheckerTest(Integer inputNumber,
                                  Boolean expectedResult) {
        this.inputNumber = inputNumber;
        this.expectedResult = expectedResult;
    }

    /**
     * 步骤四:为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为
     * java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对
     *   1)该方法必须由Parameters注解修饰
     2)该方法必须为public static的
     3)该方法必须返回Collection类型
     4)该方法的名字不做要求
     5)该方法没有参数
     */
    @Parameterized.Parameters
    public static Collection primeNumbers() {
        return Arrays.asList(new Object[][]{
                {2, true},
                {6, false},
                {19, true},
                {22, false},
                {23, true}
        });
    }

    @Before
    public void initialize() {
        primeNumberChecker = new PrimeNumberChecker();
    }

    /**
     * 步骤五:编写测试方法,使用自定义变量进行测试
     */
    @Test
    public void testPrimeNumberChecker() {
        System.out.println("Parameterized Number is : " + inputNumber);
        Assert.assertEquals(expectedResult,
                primeNumberChecker.validate(inputNumber));
    }
}


Junit 执行原理

分两种方式执行Junit 测试

  • IDEA 或者eclipse 里面执行,在test类里面右键–》执行
  • 直接通过命令执行 ,java org.junit.runner.JUnitCore 测试类的名字
1. IDEA 或者eclipse 里面执行原理

在执行JUnit测试用例之前,Eclipse将会为这个测试类找到合适的Runner。
这里给出了5种RunnerBuilder,它们会被按顺序依次遍历,找到一个合适的Runner后即停止:

  • IgnoreBuilder。检查被测类是否含有@Ignore注解,如果有,则初始化一个IgnoredClassRunner,否则返回null。
  • AnnotatedBuilder。检查被测类是否含有@RunWith注解,如果有,则用该注解的value初始化一个Runner,否则返回null。
  • SuiteMethodBuilder。检查被测类是否含有一个叫“suite”的方法,如果有,则初始化一个SuiteMethod(这是JUnit3.8中使用的Runner),否则返回null。
  • JUnit3Builder。检查被测类是否是TestCase的子类,如果是,则初始化一个JUnit38ClassRunner,否则返回null。
  • JUnit4Builder。没有检查条件。将初始化一个BlockJUnint4ClassRunner。这也是JUnit4默认的Runner。

经过这5步,必然会找到一个Runner,我们这个了例子就会返回BlockJUnit4ClassRunner。接下来,我们看看这个JUnit4ClassRunner中发生了什么。
最关键的地方是BlockJUnit4ClassRunner.run()方法:

Statement statement = classBlock(notifier);
statement.evaluate(); // Would trigger the whole test case execution flow.

第一句用于生成一个Statement对象,这个对象里面封装了类级别(classBlock)和方法级别(methodBlock)的所有注解相关的信息。

第二句statement.evaluate()方法将触发整个链式调用,将会按照组合的先后顺序倒序执行,比如,生成Statement的顺序为:

Statement statement = childrenInvoker(notifier);
statement = withBeforeClasses(statement);
statement = withAfterClasses(statement);
statement = withClassRules(statement);

那么在执行evaluate方法的时候:

会先将Statement看做是RunRules并调用其evaluate,
这会把Statement看做是RunAfters并调用其evaluate,
这又会把Statement看做是RunBefores并会调用其evalueate,
这样又会调用childrenInvoker返回的Statement的evaluate,而这是一个回调函数,即会调用runChildren(notifier);
遍历所有的用例并为每个用例调用runChild(each, notifier);
runChild()方法会调用runLeaf()方法(里面也同样是倒叙执行的过程),以完成一个用例的执行。

2. 直接通过命令执行
java org.junit.runner.JUnitCore 测试类的名字

这里的org.junit.runner.JUnitCore类来自junit.jar包,它里面的main方法就是整个程序的入口了,一起看看源代码:

public class JUnitCore {
private final RunNotifier notifier = new RunNotifier();

/**
 * Run the tests contained in the classes named in the <code>args</code>.
 * If all tests run successfully, exit with a status of 0. Otherwise exit with a status of 1.
 * Write feedback while tests are running and write
 * stack traces for all failed tests after the tests all complete.
 *
 * @param args names of classes in which to find tests to run
 */
public static void main(String... args) {
    Result result = new JUnitCore().runMain(new RealSystem(), args);
    System.exit(result.wasSuccessful() ? 0 : 1);
}
// Ignore other codes

}
args参数即为我们指定的要执行的测试类名字,这里为TestA。可以看见,main方法中创建了一个JUnitCore实例,然后调用runMain()方法:

Result runMain(JUnitSystem system, String… args) {
system.out().println("JUnit version " + Version.id());
JUnitCommandLineParseResult jUnitCommandLineParseResult =
JUnitCommandLineParseResult.parse(args);
RunListener listener = new TextListener(system);
addListener(listener);
return run(jUnitCommandLineParseResult.createRequest(defaultComputer()));
}
runMain方法第一句输出了JUnit的版本信息,这和上图的执行结果一致。接下来调用了run()方法:

public Result run(Request request) {
return run(request.getRunner());
}
public Result run(Runner runner) {
Result result = new Result();
RunListener listener = result.createListener();
notifier.addFirstListener(listener);
try {
notifier.fireTestRunStarted(runner.getDescription());
runner.run(notifier); // !!!IMPORTANT!!!
notifier.fireTestRunFinished(result);
} finally {
removeListener(listener);
}
return result;
}
可见,最终还是调用了Runner.run方法。由于这个该方法是一个抽象函数,那么,程序是如何知道最终应该调用默认的BlockJUnit4ClassRunner的run方法呢?

答案就在这个jUnitCommandLineParseResult.createRequest方法中:

public Request createRequest(Computer computer) {
if (parserErrors.isEmpty()) {
Request request = Request.classes(
computer, classes.toArray(new Class<?>[classes.size()]));
return applyFilterSpecs(request);
} else {
return errorReport(new InitializationError(parserErrors));
}
}
这里面又调用了Request.classes()方法来创建一个request:

public static Request classes(Computer computer, Class<?>… classes) {
try {
// Note this builder, it is the same as the 2nd screenshot.
AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true);
Runner suite = computer.getSuite(builder, classes);
return runner(suite);
} catch (InitializationError e) {
throw new RuntimeException(
“Bug in saff’s brain: Suite constructor, called as above, should always complete”);
}
}

Mockito单元测试

Mockito是mocking框架,它让你用简洁的API做测试。而且Mockito简单易学,它可读性强和验证语法简洁。
Mockito 是一个针对 Java 的单元测试模拟框架,它与 EasyMock 和 jMock 很相似,都是为了简化单元测试过程中测试上下文 ( 或者称之为测试驱动函数以及桩函数 ) 的搭建而开发的工具

常用的 Mockito 方法:

在这里插入图片描述

使用 Mockito 通常有两种常见的方式来创建 Mock 对象。

1、使用 Mockito.mock(clazz) 方式
通过 Mockito 类的静态方法 mock 来创建 Mock 对象,例如以下创建了一个 List 类型的 Mock 对象:
List mockList = Mockito.mock(ArrayList.class);
由于 mock 方法是一个静态方法,所以通常会写成静态导入方法的方式,即 List mockList = mock(ArrayList.class)。

2、使用 @Mock 注解方式
第二种方式就是使用 @Mock 注解方式来创建 Mock 对象,使用该方式创需要注意的是要在运行测试方法前使用 MockitoAnnotations.initMocks(this) 或者单元测试类上加上 @ExtendWith(MockitoExtension.class) 注解

示列一

package com.xsz.mockito;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.ArrayList;
import java.util.List;
//为了代码测试的方便,直接在测试类中静态导入
import static org.mockito.Mockito.*;



public class MockitoDemo1 {

    @Test
    public void testMockBase(){
        //创建ArrayList的Mock对象
        List mockList = mock(ArrayList.class);
        //pass
        Assert.assertTrue(mockList instanceof ArrayList);

        //当我们mockList调用方法去add("张三")的时候会返回true
        when(mockList.add("张三")).thenReturn(true);
        //当我们mockList调用方法size()的时候返回10
        when(mockList.size()).thenReturn(10);
        //pass
        Assert.assertTrue(mockList.add("张三"));
        //pass
        Assert.assertFalse(mockList.add("李四"));
        //pass
        Assert.assertEquals(mockList.size(),10);
        //null
        System.out.println(mockList.get(0));
    }


    @Test
    public void simpleTest(){
        //创建mock对象,参数可以是类,也可以是接口
        List<String> list = mock(List.class);
        //设置方法的预期返回值
        when(list.get(0)).thenReturn("helloworld");
        String result = list.get(0);
        //验证方法调用(是否调用了get(0))
        verify(list).get(0);
        //junit测试
        Assert.assertEquals("helloworld", result);
    }

    @Test
    public void argumentMatcherTest(){
        List<String> list = mock(List.class);
        when(list.get(anyInt())).thenReturn("hello","world");
        String result = list.get(0)+list.get(1);
        verify(list,times(2)).get(anyInt());
        Assert.assertEquals("helloworld", result);
    }

}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值