JUnit 单元测试小结

JUnit单元测试小结

单元测试关注单一的类,目的:检查这个类中的代码是否按照期望正确运行。

基本概念

单元测试

在单元测试中, 我们需要保证被测系统是独立的, 即当被测系统通过测试时, 那么它在任何环境下都是能够正常工作的。编写单元测试时, 不需要关注例如数据库服务, Web 服务等组件。

被测系统SUT

被测系统(System under test, SUT)表示正在被测试的系统, 目的是测试系统能否正确操作。 SUT可以是一个类甚至是一整个系统。

测试依赖组件DOC

被测系统所依赖的组件, 例如进程 UserService 的单元测试时, UserService 会依赖 UserDao, 因此 UserDao 就是 DOC。

测试替身Test Double

一个实际的系统会依赖多个外部对象,单元测试时用功能简单且行为类似的假对象来作为 SUT 的依赖对象,这些假对象就被称为 测试替身(Test Double)。
测试替身分5种:
  • Test stub , 为SUT提供数据的假对象
  • Fake object , 实现了简单功能的假对象
    测试时某些组件不可用或运行速度太慢, 使用 Fake object 来代替它们。
  • Mock object
    用于模拟实际的对象, 并且能够校验对这个 Mock object 的方法调用是否符合预期
    可以灵活地配置所调用的方法所产生的行为, 并且可以追踪方法调用,如传递了什么参数,调用了几次等。
  • Dummy object, 测试没有使用到的、仅仅是为了填充参数列表的对象
  • Test Spy
    可以包装一个真实的 Java 对象, 并返回一个包装后的新对象。 若没有特别配置的话, 对这个新对象的所有方法调用, 都会委派给实际的 Java 对象。
    与mock的区别:mock无中生有,所有方法都是虚拟的;spy 则是在现有类的基础上包装了一个对象。

Test fixture

运行测试程序所需要的先决条件(precondition)。
JUnit4中使用 @Before 代替 setUp 方法, @After 代替 tearDown 方法。
如果只需要初始化一次则使用 @BeforeClass 和 @AfterClass。

测试用例Test case

JUnit4中被 @Test 标注的方法就是执行测试用例的测试方法

测试套件

通过 TestSuit 对象将多个测试用例组装成一个测试套件, 测试套件批量运行
通过@RunWith 和@SuteClass 两个注解, 我们可以创建一个测试套件。通过@RunWith 指定一个特殊的运行器, 即 Suite.class 套件运行器, 并通过@SuiteClasses 注解, 将需要进行测试的类列表作作为参数传入。

例子

  1. 添加依赖
点击查看代码
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>
  1. 测试套件
点击查看代码
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestJunit {
    @Test
    public void testingCrunchifyAddition() {
        assertEquals("Here is test for Addition Result: ", 30, addition(27, 3));
    }

    @Test
    public void testingHelloWorld() {
        assertEquals("Here is test for Hello World String: ", "Hello + World", helloWorld());
    }

    public int addition(int x, int y) {
        return x + y;
    }

    public String helloWorld() {
        String helloWorld = "Hello +" + " World";
        return helloWorld;
    }
}
  1. 测试用例
点击查看代码
public class App {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(TestJunit.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        if (result.wasSuccessful()) {
            System.out.println("Both Tests finished successfully...");
        }
    }
}

JUnit4生命周期

  • 类级 初始化资源处理 每一个测试用例类仅执行一次
  • 方法级 初始化资源处理 每个测试方法中都会被执行一次
  • 执行测试用例中的方法
  • 方法级 销毁资源处理 每个测试方法中都会被执行一次
  • 类级 销毁资源处理 每一个测试用例类仅执行一次

单元测试包含内容

  1. 接口功能性测试: 接口功能的正确性,即保证接口能够被正常调用,并输出有效数据
  • 是否被顺利调用
  • 参数是否符合预期
  1. 局部数据结构测试:保证数据结构的正确性
  • 变量是否有初始值或在某场景下是否有默认值
  • 变量是否溢出
  1. 边界条件测试:
  • 变量无赋值(null)
  • 变量是数值或字符
  • 主要边界:最大值,最小值,无穷大
  • 溢出边界:在边界外面取值+/-1
  • 临近边界:在边界值之内取值+/-1
  • 字符串的边界,引用 "变量字符"的边界
  • 字符串的设置,空字符串
  • 字符串的应用长度测试
  • 空白集合
  • 目标集合的类型和应用边界
  • 集合的次序
  • 变量是规律的,测试无穷大的极限,无穷小的极限
  1. 所有独立代码测试:保证每一句代码,所有分支都测试完成,主要包括代码覆盖率,异常处理通路测试
  • 语句覆盖率:每个语句都执行到了
  • 判定覆盖率:每个分支都执行到了
  • 条件覆盖率:每个条件都返回布尔
  • 路径覆盖率:每个路径都覆盖到了
  1. 异常模块测试,后续处理模块测试:是否包闭当前异常或者对异常形成消化,是否影响结果

参考:
https://segmentfault.com/a/1190000006731125
https://blog.csdn.net/qq_36505948/article/details/82797240

posted @ 2021-09-23 10:36  zjcfrancis  阅读(332)  评论(0编辑  收藏  举报