Junit5单元测试

本文介绍了单元测试的核心原则AIR和BCDE,并详细讲解了Junit5的测试覆盖率、注解使用以及断言和假设。通过Junit5的@Nested、@Tag等注解实现更灵活的测试组织,使用AssertJ增强断言能力,提高测试质量。

单元测试理念


单元测试的基本原则

宏观上,符合AIR原则

  • A: Automatic(自动化)
    • 需全自动执行,不需要人工介入检查
    • 不允许使用System.out进行人工验证,用断言
  • I:Independent(独立性)
    • 测试用例不允许互相调用
    • 不允许出现执行次序的依赖
  • R:Repeatable(可重复)
    • 每次代码修改后,可以重复利用测试用例

微观上,符合BCDE原则

  • B:Border,边界测试
    • 包括循环边界,特殊取值,特殊时间点,数据顺序
  • C:Correct,正确
    • 正确的输入,得到预期输入
  • D:Design
    • 与设计文档相结合
  • E: Error
    • 进行一下错误输入检测预期的错误结果

单元测试覆盖率


粗粒度覆盖率

  • 类覆盖
  • 方法覆盖

细粒度覆盖率

  • 行覆盖
    • 行覆盖率的计算公式的分子是执行到的语句数,分母是总的可执行语句
  • 分支覆盖率
  • 条件判定覆盖
  • 条件组合覆盖
  • 路径覆盖

Junit5系列


介绍

  • JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
    • JUnit Platform 作为在JVM上启动测试框架的基础。
    • JUnit Jupiter 是新的编程模型和扩展模型的组合,JUnit 5中类都在此包中
    • Unit Vintage 为在平台上运行基于JUnit 3和JUnit 4的测试提供了一个测试引擎。
Maven导入Junit5
<dependencies>
   <!--导入Junit5依赖-->
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-launcher</artifactId>
        <version>1.2.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.2.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>5.2.0</version>
        <scope>test</scope>
    </dependency>
    
    <!--参数化测试需要添加==junit-jupiter-params== 模块-->
    <dependency>
		<groupId>org.junit.jupiter</groupId>
		<artifactId>junit-jupiter-params</artifactId>
		<version>5.2.0</version>
		<scope>test</scope>
	</dependency>
</dependencies>

注解

  • @Test

    • Junit框架会在测试阶段自动找出所有使用该注解表明的方法并运行。
     @Test
      void myFirstTest() {
          Assertions.assertEquals(11,12);
      }
    
  • @DisplayName

    • 定义测试方法和类的名称。
    • 测试类和测试方法可以声明自定义显示名称,将由测试运行器和测试报告显示
    @DisplayName("测试类名")
    public class DisplayNameTest {
      @Test
      @DisplayName("测试方法")
      void testWithDisplayNameContainingSpaces() {
      }
    }
    
  • @Disabled

    • 注明一个测试类或方法不再运行
    //整个类不再运行
    @Disabled
    class DisabledClassDemo {
      。。。
    }
    
    //单个方法不再运行
    class DisabledTestsDemo {
      @Disabled
      @Test
      void testWillBeSkipped() {
      }
    }
    
  • @BeforeEach

    • 在每一个测试方法运行之前,运行指定的方法
  • @AfterEach

    • 在每一个测试方法运行之后,运行指定的方法
  • @BeforeAll

    • 在每一个测试类运行之前,都运行一个指定的方法
  • @AfterAll

    • 在每一个测试类运行之后,都运行一个指定的方法
  • @Nested

    • 为测试添加嵌套层级
  • @Tag

    • 为测试类或方法添加标签,以便有选择性的运行。
  • @ParameterizedTest

    • 参数化测试,作用类似于@Test,但可以让一个方法使用不同的入参运行多次
    • 必须声明至少一个参数源,该源将为每个调用提供参数。
      • @ValueSource
      • @EnumSource
      • @MethodSource
      • @ArgumentsSource
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.CsvSource;
    import static org.assertj.core.api.Assertions.*;
    public class DemoApplicationTests {
      @ParameterizedTest
      @DisplayName("测试方法")
      @CsvSource({
              "1, 2, 3",
              "2 ,3, 4",
              "2, 5, 100"
      })
      void myFirstTest(int a, int b, int c) {
          assertThat(a).isLessThan(3);
       }
    }
    

断言与假设

普通断言

  • 常用的断言被封装在org.junit.jupiter.api.Assertions类中 ,均为静态方法
方法释义
Assertions.fail()运行到这句表示测试失败
Assertions.assertTrue(a == 100) / Assertions.assertFalse(…)断言条件为真或为假
Assertions.assertNull(object) / Assertions.assertNotNull(object)断言对象为空/非空
Assertions.assertEquals(…) / Assertions.assertNotEquals(…);指定值是否相等,基本数据类型比较值,对象会调用equals()方法比较
Assertions.assertArrayEquals()断言数组元素全部相等
Assertions.assertSame(); / Assertions.assertNotSame();两个对象是否为同一个对象
Assertions.assertThrows() / Assertions.assertDoseNotThrow()断言是否抛出一个特定类型异常
Assertions.assertTimeout()断言超时,超时后继续执行
Assertions.assertIterableEquals();断言迭代器中的元素全部相等
Assertions.assertLinesMatch();断言字符串列表全部相等
Assertions.assertAll();多个条件同时满足

普通假设

  • 假设都是在 org.junit.jupiter.api.Assumptions 的静态方法。
  • 假设与断言类似,只不过当条件不满足时,测试会直接退出而不是认定为测试失败,最终记录的状态为跳过。
方法释义
assumeTrue / assumeFalse判定真假

AssertJ流式断言-第三方断言库

  • 加入依赖
    <dependency>
		<groupId>org.assertj</groupId>
		<artifactId>assertj-core</artifactId>
		<scope>test</scope>
		<version>3.9.1</version>
    </dependency>
  • 流式测试
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;

@DisplayName("测试类名")
public class DemoApplicationTests {
    @Test
    @DisplayName("测试方法")
    void myFirstTest(int a) {
        assertThat("test").isNotBlank() // 是否为" "字符串
				.as("字符串断言描述").isSubstringOf("test1") // 是否为test1的一部分
				.isSameAs("test") // 对象内元素是否相等
				.isNotEmpty() // 是否为空字符串
				.isEqualTo("test") // 是否相等
				.isEqualToIgnoringCase("Test") // 是否相等(忽略大小写)
				.isExactlyInstanceOf(String.class) // 是否是实例
				.isIn(Arrays.asList("test", "hello")) // 是否在列表中
				.isIn("test", "hello") // 是否在参数列表中
				.isInstanceOfAny(String.class, Integer.class) // 是否是实例中任何一个
				.isNotNull() // 是否不为空
				.contains("es") // 是否包含es子串
				.startsWith("te") // te开始
				.endsWith("st") // st结束
				.matches(".e.t"); // 是否匹配 .e.t 格式
				
		assertThat("").isNullOrEmpty();
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值