单元测试笔记

前言

最近写很多单元测试 一直没记录
今天整理一下 常见的demo 方便后续速查

https://junit.org/junit5/docs/current/user-guide/#overview

JUnit5注解汇总

基础测试控制
注解含义使用场景
@Test标记测试方法单个测试逻辑的验证
@BeforeEach每个测试方法前执行初始化测试环境
@AfterEach每个测试方法后执行清理测试环境
@BeforeAll整个测试类执行前运行初始化全局资源
@AfterAll整个测试类执行后运行清理全局资源
@Disabled禁用测试方法暂时跳过测试
@Tag标记测试,支持按标签执行组织和筛选测试
@DisplayName设置显示名称提高测试输出可读性
参数化测试
注解含义使用场景
@ParameterizedTest参数化的测试验证不同输入值的行为
@ValueSource提供固定值作为参数参数列表
@EnumSource提供枚举值作为参数枚举遍历
@CsvSource / @CsvFileSourceCSV数据作为参数数据驱动测试
测试控制和异常测试
注解含义使用场景
@RepeatedTest重复执行测试验证稳定性
@AssertThrows验证方法抛出预期异常异常处理测试
扩展和定制
注解含义使用场景
@TestExtension定义测试扩展自定义测试行为
@RegisterExtension注册测试扩展使用自定义扩展
@TempDir提供临时目录存储临时文件
@Import引入额外配置类测试上下文扩展

mockito

注解作用使用场景
@Mock创建一个模拟对象,可以控制其行为和返回值。当需要隔离测试,不依赖真实对象时。
@Spy创建一个真实对象的代理,可以部分模拟,其他行为保持不变。当需要测试部分真实行为,同时控制某些方法时。
@InjectMocks自动注入依赖,通常用于创建被测试对象,其中依赖项由@Mock@Spy注解的实例填充。当测试类需要依赖模拟对象时。
@Captor配合ArgumentCaptor使用,捕获方法调用的参数。当需要验证方法调用的参数时。
@RunWith(MockitoJUnitRunner.class)使用Mockito运行器,初始化@Mock@Spy注解的实例。在JUnit测试类中使用,代替@Before初始化模拟对象。
@Before初始化方法,通常用于配置模拟对象。需要在每个测试方法之前执行的初始化逻辑。
@After清理方法,通常用于清理模拟对象。需要在每个测试方法之后执行的清理逻辑。
@MockBeanSpring Boot测试中创建模拟的Spring Bean。当测试需要模拟Spring容器中的Bean时。
@SpyBeanSpring Boot测试中创建真实Bean的代理,可以部分模拟。当测试需要部分模拟Spring容器中的Bean时。
@WithMockUserSpring Security测试中模拟登录用户的身份。当测试需要模拟不同用户权限时。
@MockitoSettings控制Mockito框架的全局设置,如严格性、默认答案等。当需要自定义Mockito的行为时。
@ExtendWith(MockitoExtension.class)JUnit 5中初始化Mockito,替代@RunWith(MockitoJUnitRunner.class)在JUnit 5测试类中使用。
Mockito 主要类和函数
Mockito 类与函数
类名函数描述
Mockitomock(Class<T> classToMock)创建模拟对象,不执行实际操作。
when(T toMock)定义模拟对象的行为,设置方法调用的返回值或行为。
thenReturn(T value)模拟方法调用时返回指定值。
thenThrow(Throwables... toThrow)模拟方法调用时抛出异常。
doAnswer(Answer answer)自定义方法调用的处理逻辑。
doNothing()方法调用不执行任何操作,不返回值。
doCallRealMethod()使模拟方法调用实际实现。
verify(T mock)验证模拟对象的方法是否被调用。
verifyNoMoreInteractions(Object... mocks)验证没有其他未验证的交互。
verifyZeroInteractions(Object... mocks)验证模拟对象未被调用。
ArgumentMatchers 辅助类
函数描述
any()匹配任何参数值。
anyVararg()匹配任何变长参数。
eq(T value)匹配与给定值相等的参数。
Assertions 主要方法
JUnit Jupiter (org.junit.jupiter.api.Assertions)
方法描述
assertEquals(expected, actual)验证预期值与实际值相等。
assertNotEquals(expected, actual)验证预期值与实际值不相等。
assertTrue(condition)验证条件为真。
assertFalse(condition)验证条件为假。
assertNull(object)验证对象为 null。
assertNotNull(object)验证对象非 null。
assertSame(expected, actual)验证预期对象与实际对象是同一个对象。
assertNotSame(expected, actual)验证预期对象与实际对象不是同一个对象。
assertAll(Executable... executables)批量执行多个断言。

示例

  • 基本依赖 starter包包含了 junit5和mockito
    testImplementation "org.springframework.boot:spring-boot-starter-test"
  • 基本单元测试格式
package com.ming;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
public class DemoTest {
    @BeforeEach
    public void init() {
        System.out.println("init");
    }

    @AfterEach
    public void destroy() {
        System.out.println("destroy");
    }

    @Test
    public void test() {
        System.out.println("test");
    }
}
  • mock静态方法

mock静态方法 以前是用powermock junit5之后 mockito也提供mock的方式

   // https://mvnrepository.com/artifact/org.mockito/mockito-inline
   testImplementation group: 'org.mockito', name: 'mockito-inline', version: '5.2.0'

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

@ExtendWith(SpringExtension.class)
public class MockStaticTest {
    private MockedStatic<StaticTestService> mockStatic;
    @BeforeEach
    public void setUp() {
        mockStatic = org.mockito.Mockito.mockStatic(StaticTestService.class);
    }

    @AfterEach
    public void tearDown() {
        mockStatic.close();
    }

    @Test
    public void testNoArg() {
        mockStatic.when(StaticTestService::testNoArg).thenReturn("test");
        assertEquals("test", StaticTestService.testNoArg());
    }

    @Test
    public void testArg() {
        mockStatic.when(() -> StaticTestService.testArg("arg")).thenReturn("test");
        assertEquals("test", StaticTestService.testArg("arg"));
        assertNotEquals("test", StaticTestService.testArg("arg1"));
    }
}

class StaticTestService {
    public static String testNoArg() {
        return "????";
    }

    public static String testArg(String str) {
        return "????";
    }
}
  • mock私有变量

ReflectionTestUtils.setField(testService, “字段名”, “字段赋值”);


import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(SpringExtension.class)
public class MockTest {
    @InjectMocks
    private TestService testService;

      @Test
    public void test() {
        assertEquals("????ming-default", testService.getStr());
        ReflectionTestUtils.setField(testService, "str", "ming-update");
        assertEquals("????ming-update", testService.getStr());
    }
}

class TestService {
    private String str = "ming-default";

    public String getStr() {
        return "????" + str;
    }
}
  • mock MybatisPlus Mapper

如果用到lambdaXXXXX 需要注入 TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), “”), xxxxEntity.class);

总结

就是常见的单元测试方法
junit5 已经成为一个java的单元测试平台了
常见的操作 基本覆盖 配合mockito基本够用

© 2024 ming博客. All rights reserved.基于rust salvo性能猛的很!