概述

  • Test Case

    • 用来测试一段代码(类的方法)的最小单元
  • 测试一个问题

    • 最少需要两个 Test Case

      • 一个“正确”的结果测试 positive
      • 一个“失败”的结果测试 negative

junit 安装

  • 不需要具体安装
  • 放到依赖中即可

运行

  • 使用 JUnitCore.run(your_test_class.class) 运行

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
      import org.junit.runner.JUnitCore;
      import org.junit.runner.Result;
      import org.junit.runner.notification.Failure;
    
      public class TestRunner {
    public static void main(String[] args) {
     Result result = JUnitCore.runClasses(TestJunit.class);
    
     for (Failure failure : result.getFailures()) {
        System.out.println(failure.toString());
     }
    
     System.out.println(result.wasSuccessful());
    }
      }

组件

  • Fixtures
  • Test suites
  • Test runners
  • JUnit classes

Fixtures 固件

  • 用途

    • 用来创建测试环境
  • 组成

    • setUp()
    • tearDown()
      • 它们分别在一个测试的开始和结束时运行

<<Test Fixture Example>>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  import junit.framework.*;

  public class JavaTest extends TestCase {
protected int value1, value2;

// assigning the values
protected void setUp(){
 value1 = 3;
 value2 = 3;
}

// test method to add two values
public void testAdd(){
 double result = value1 + value2;
 assertTrue(result == 6);
}
  }

Test Suites

比 Test Case 更高一级的组织

  • 作用

    • 用来包裹 Test Cases
  • 特性

    • Test Suite 类,其中的代码可以为空

      • 毕竟,它只是一个组织结构的壳

<<Test Suite Example>>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  import org.junit.runner.RunWith;
  import org.junit.runners.Suite;

  //JUnit Suite Test
  @RunWith(Suite.class)
  @Suite.SuiteClasses({ 
     TestJunit1.class ,TestJunit2.class
  })
  public class JunitTestSuite {
  }

注解

  • @RunWith
  • @Suite.SuiteClasses

    • 指定包含的 Test Cases

Test Runners

  • 运行的入口
  • 包含 main 方法

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
      import org.junit.runner.JUnitCore;
      import org.junit.runner.Result;
      import org.junit.runner.notification.Failure;
    
      public class TestRunner {
    public static void main(String[] args) {
     Result result = JUnitCore.runClasses(TestJunit.class);
    
     for (Failure failure : result.getFailures()) {
    System.out.println(failure.toString());
     }
    
     System.out.println(result.wasSuccessful());
    }
      }

相关的类

Assert

  • org.junit.runner.Assert

    1
    
    import static org.junit.runner.Assert.assertEquals
    • 包含许多测试方法,如:assertEquals

TestCase

  • 一个自定义的类 或者 继承了 junit.framework.TestCase 的类
  • 包含一个个的测试用例
    • 只有 继承了 TestCase 类,才能有 setUp() 和 tearDown() 固件
    • 不继承 TestCase 类,测试用例需要使用@Test 标注
    • ref: Test Fixture Example

TestResult

  • org.junit.runner.Result
  • 用来包含 Test Cases 测试的结果
  • 注意

    • 这里是存放一整个 TestCase 的结果

Failure

  • org.junit.runner.notification.Failure
  • 用来存放一个失败的测试用例
  • 注意

    • 这里存放的是一个测试用例的失败
    • 不是一整个 Test Case

TestCase 抽象类

1
  public abstract class TestCase extends Assert implements Test
  • 用例不需要加 @Test
  • 直接使用 Assert 类的方法

常见注解

https://www.cnblogs.com/flypig666/p/11505277.html

  • 位置

    • org.junit

@Before

  • 每一个测试方法执行之前,执行一次

@After

  • 每一个测试方法执行之后,执行一次

@BeforeClass

  • 所有测试方法执行之前,执行一次

@AfterClass

  • 所有测试方法执行之后,执行一次

@Test

  • 标注测试方法

属性

  • expected

    • 可能发生的异常
1
  @Test(expected=ArithmeticException.class)
  • timeout

    • 单位:毫秒

执行顺序

@BeforeClass -> @Before -> @Test -> @After -> @AfterClass

@Ignore

  • 不会被执行的测试
  • 特性

    • 即使和@Test 一起注解,也是@Ignore 生效
  • 作用对象

    • 方法

Assert

https://junit.org/junit4/javadoc/latest/org/junit/Assert.html

  • 位置

    • org.junit.Assert
  • 方法

    • equal

      • assertEquals()
      • assertArrayEquals()
      • assertSame()
  • 判断是否是指向同一个对象

    • null

      • assertNull()
      • assertNotNull()
    • true or false

      • assertTrue()
      • assertFalse()
    • 通配 assert

      • assertThat

assertThat

https://blog.csdn.net/smxjant/article/details/78206435

总结性说明 https://www.cnblogs.com/shangren/p/8039215.html

相关依赖

CoreMathers 官方文档

  • org.hamcrest.CoreMatchers

    • 其中的静态方法

一般匹配符

  • 作用

    • 逻辑运算
    • 包装其它运算符
  • &&: 与

    • allOf()
  • : 或
    • anyOf()
  • true

    • anything()
  • not: 非

    • not()
  • is: 是

    • is()
  • both()

    • 与的特例
    • assertThat("fab", both(containsString("a")).and(containsString("b")))
  • either()

    • 或的特例
    • assertThat("fan", either(containsString("a")).and(containsString("b")))

字符串匹配

数值匹配

  • 约等于

    • closeTo(num, tolerant)
  • >

    • greaterThan(num)
  • <

    • lessThan(num)
  • >=

    • greaterThanOrEqualTo(num)
  • <=

    • lessThanOrEqualTo(num)
  • ==

    • equalTo(num)
    • 注:
  • 我还没有进行验证是否成立

集合匹配 collections

  • hasEntry(key, value)
  • hasItem(value)
  • hasItems(…valueList)
  • hasKey(key)
  • hasValue(value)
  • everyItem()

    1
    
      assertThat(Arrays.asList("bar", "baz"), everyItem(startsWith("ba")))

引用匹配

  • nullValue()

    • assertThat(cheese, is(nullValue()))
  • notNullValue()
  • sameInstance(target)
  • theInstance(target)

    • 与 sameInstance(target) 一样

JUnitCore

  • 运行测试的门面
  • 运行

    1
    
      JUnitCore.runClasses(Class<?> ...yourClasses)
    • 运行提供的类中包含的测试

TestSuite 类

完整创建

简洁使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  import junit.framework.*;

  public class JunitTestSuite {
public static void main(String[] a) {
 // add the test's in the suite
 TestSuite suite = new TestSuite(TestJunit1.class, TestJunit2.class, TestJunit3.class );
 TestResult result = new TestResult();
 suite.run(result);
 System.out.println("Number of test cases = " + result.runCount());
}
  }
  • 步骤

    1. 使用 TestSuite 对象,包裹多个 TestCase
    2. 创建 TestResult
    3. 使用 TestSuite 对象,运行 TestResult 对象

参数化测试,重复多次测试

结合步骤研究 https://www.tutorialspoint.com/junit/junit_parameterized_test.htm

  • 步骤

    1. 测试类,使用@RunWith(Parameterized.class) 标注
    2. 创建 “静态方法”static, 使用◎Parameters 标注

      • 需要返回 Array 类型 数据
  • 用于测试的输入,和检验数据

    1. 创建 public 构造函数

      • 用于接收一行数据(来自前面的 static 方法)
    2. 创建实例变量,用来存储各个列的数据

      • 在构造函数中创建和赋值
    3. 创建测试方法

      • 其中使用的输入数据和验证数据,就是之前创建的实例变量

org.junit Vs. junit.framework

  • org.junit 属于 JUnit 4+
  • junit.framework 属于老版本

JUnit 4

https://github.com/junit-team/junit4/wiki/Getting-started

编译

1
  javac -cp .;junit-4.XX.jar;hamcrest-core-1.3.jar CalculatorTest.java

运行

1
  java -cp .;junit-4.XX.jar;hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorTest

@Rule

简介 https://www.jianshu.com/p/e74ca1b42730

用法详细 https://blog.csdn.net/weixin_34399060/article/details/93886426

  • 特性

    • 在每一个测试方法之前执行类似@Before
    • 可以在多个测试类中使用,提高代码重用性
    • 一种更高级的管理 各个测试方法 声明周期 的管理工具

内置 TestRule 类

  • Verifier

    • 测试方法执行结束后,使用 Verifier.verify() 进一步验证
  • ErrorCollector

    • 用于收集错误信息
    • 相关方法

      • collectorObj.addError(new RuntimeException("error 1"))
  • TemporaryFolder

    • 临时目录工具
  • TestName

    • 测试方法名称获取工具
    • 相关方法

      • testNameObj.getMethodName()
  • TestWacher

    • 测试方法全声明周期,监测工具
  • Timeout

    • 超时工具
    • 与@Test(timeout=..)类似

      • 但是,修饰的是整个类
  • ExpectedException

    • 异常处理工具
    • 类似@Test(expected=…)

      • 但是,更灵活,因为是可以在代码里修改,而@Test 只是注解 + 名称

自定义 TestRule

  • 完整的类
  • 匿名类

Java Mock 测试工具(Mockito)

入门简介写的好 https://www.cnblogs.com/bodhitree/p/9456515.html

具体用法写的详细 https://www.vogella.com/tutorials/Mockito/article.html#mockito_spy

上述文章的部份章节中文翻译版本 https://www.jianshu.com/p/f6e3ab9719b9

  • 使用虚拟对象(Mock 对象)来进行测试的方法
  • 使用环境

    • 有些 Java 对象特别不容易构造
    • 如 HttpServletRequest(在 Servlet 容器中才可以被创造)
    • 因此,使用模拟对象的方法,很方便
  • 具体使用范畴

    • 真实对象的不确定问题

      • 难以创建
      • 某些行为难以预测
      • 真实对象当前不存在
  • 如:

    • 别人正在开发中,现在还没有
    • 在研发硬件,或新硬件
    • 特性

      • 实现单元测试的解耦

        • 打断测试之间的依赖,因为模拟对象不是真的,不需要考虑依赖
    • 实现原理

      • 模拟真实对象的接口的功能

相关注解

https://www.cnblogs.com/langren1992/p/9681600.html

  • @Mock

    • 创建 Mock 对象
    • 把 new 创建的普通对象,转化成 Mock 对象
    • 类似 mock(your_class.class)
  • @Spy

    • 把普通对象转化成 “部份 Mock”对象
    • 类似 spy(your_object)
  • @InjectMock

    • 依赖注入
    • 把给定变量,关联到 Mock 对象

      • 如果还没有创建 Mock 对象
  • 相当于 自动生成了 mock(your_class.class) 对象

    • 如果 构造函数 需要参数
  • 这些参数也会被自动绑定到 Mock 对象

    • @RunWith