Java单元测试(Mock)

本文详细介绍了如何在Java开发中使用JUnit、SpringTest、Mockito和MockMvc进行单元测试,涵盖了单元测试的基本概念、Mockito创建模拟对象的方法、SpringBootTest的注解及其在测试中的作用,以及如何利用参数化测试、断言和模拟HTTP请求进行有效测试。
摘要由CSDN通过智能技术生成

概念

单元测试,用于检查和验证程序中的各个单元(通常是函数、方法或类)是否按照预期工作(是否符合预期)。

解释
JUnit单元测试框架,提供了一组注解和断言来编写和运行测试
Spring Test和SpringBootTest提供了一些方便的工具和注解来进行集成测试和组件测试。
AssertJ断言库,提供了丰富的断言来编写清晰、易读的测试代码。
Hamcrest匹配器库,用于编写灵活和可读的断言。
Mockito用于创建和管理模拟对象,帮助模拟外部依赖、行为和状态。

注解

  1. @SpringBootTest:用于加载Spring应用程序上下文。
  2. @AutoConfigureMockMvc:用于自动配置MockMvc实例。
  3. @Transactional:开启事务功能。
  4. @Rollback()事务回滚,默认true。
  5. @ParameterizedTest :用于支持参数化测试@CsvSource@ValueSource@MethodSource
  6. @Mock:创建模拟对象。
  7. @MockBean:创建模拟对象,会注入到 Spring 上下文。
  8. @Spy:创建真实对象,并可以部分模拟该对象的行为。
  9. @InjectMocks标记一个待测对象(被测试类的对象),用于注入被测试类中的依赖(注入模拟对象)

Assertions

JUnit测试中,Assertions类提供了一系列用于验证测试结果的静态方法

  1. assertEquals(expected, actual):验证两个值是否相等。适用于比较基本数据类型、对象或数组等。

    assertEquals(5, result); // 比较整数值
    assertEquals("expected", result); // 比较字符串值
    assertEquals(expectedObject, actualObject); // 比较对象
    assertEquals(expectedArray, actualArray); // 比较数组
    
  2. assertTrue(condition):验证给定的条件是否为真。

  3. assertFalse(condition):验证给定的条件是否为假。

  4. assertNull(object):验证给定对象是否为空。

  5. assertNotNull(object):验证给定对象是否不为空。

  6. assertSame(expected, actual):验证两个对象引用是否指向同一个对象。

  7. assertNotSame(unexpected, actual):验证两个对象引用是否指向不同的对象。

  8. assertThrows(expectedType, executable):验证代码块是否抛出了指定类型的异常。

单元测试步骤

注意Controller层的单元测试,可以使用MockMvc模拟HTTP请求。

  1. 准备测试数据:在测试方法之前,准备好必要的测试数据,包括输入参数、模拟的依赖对象等。
  2. 模拟依赖对象:使用Mockito等框架模拟ControllerService层依赖的其他对象,例如Repository、外部服务等。
    1. 若不使用模拟对象,直接@Autowired注入测试即可。
  3. 调用被测试的方法:在测试方法中调用ControllerService层的方法,传入准备好的测试数据。
  4. 验证行为:使用断言验证方法的行为和返回结果是否符合预期

Mock

在面向对象程序中,模拟对象(mock object)是以可控方式模拟真实对象行为假对象。

在编程过程中,通常通过模拟一些输入数据,来验证程序是否达到预期结果。

如果在单元测试中无法使用真实对象,可采用模拟对象进行替代。

MockMvc:模拟HTTP请求

MockMvc Spring提供的用于模拟HTTP请求的工具,它允许模拟请求验证控制器的行为和响应。

在单元测试和集成测试中,MockMvc 可以用来测试控制器的端到端行为,而不需要启动整个应用程序服务器。

MockMvc构造

三种方法

  1. mockMvc = MockMvcBuilders.standaloneSetup(new Testontroller()).build();
  2. mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
  3. @AutoConfigureMockMvc 注解用于自动配置 MockMvc实例。

MockMvc使用

  1. mockMvc.perform执行一个请求,返回值ResultActions
  2. MockMvcRequestBuilders.get(“/xx/xx”)构造一个get请求。
    1. MockMvcRequestBuilders类提供的各种静态方法构建不同类型的请求,如GETPOSTPUTDELETE等。
    2. contentType设置发送的数据格式
    3. accept设置返回的数据格式
    4. param添加请求传值
    5. header设置请求头
  3. ResultActions.andExpect添加执行完成后的断言
    1. 使用断言是判断结果是否符合期望
    2. 使用MockMvcResultMatchers类提供的各种静态方法构建断言,例如status()content()header()等。
    3. 使用MockMvcResultMatchers.status().isOk()来断言预期的HTTP状态码是否为200(OK)。
  4. ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情。比如处使用print()输出整个响应结果信息。
  5. ResultActions.andReturn表示执行完成后返回相应的结果

@Mock

  • @Mock 是 Mockito 框架中的注解,用于创建模拟对象
  • @Mock 只能用于普通的单元测试(例如,不涉及 Spring 应用程序上下文的测试),通常与 MockitoJUnitRunnerMockitoAnnotations.initMocks() 配合使用。
  • 它创建的模拟对象是纯粹的模拟对象,不会受到 Spring 上下文的影响,因此不会自动注入到 Spring 容器中。

@MockBean

  • @MockBean 是 Spring Boot Test 模块中的注解,用于创建模拟对象,并将其注入到 Spring 上下文中,以便在集成测试中使用。
  • @MockBean 可以用于测试 Spring 上下文中的组件,例如服务、存储库、控制器等。
  • 它创建的模拟对象是由 Spring 管理的 Bean,可以被自动注入到其他 Spring Bean 中

@Mock@MockBean区别(是否注入)

  • @Mock 用于创建纯粹的模拟对象
  • @MockBean 用于在 Spring 上下文中创建模拟对象,并将其注入到其他 Spring Bean 中,以便在集成测试中使用。

@Spy

@Spy 是 Mockito 框架中的一个注解,用于创建一个真实对象,并部分模拟该对象的行为。

@Mock 注解不同,@Spy 注解创建的对象是真实对象,但可以选择性地模拟部分方法的行为。

@InjectMocks@Mock

@InjectMocks :标记一个待测对象(被测试类的对象),用于注入被测试类中的依赖

@Mock 用于创建模拟对象@InjectMocks 用于将这些 模拟对象 注入被测试对象中,以便进行单元测试。

@ParameterizedTest注解

用于支持参数化测试。为测试方法提供一组不同的参数,以便多次运行相同的测试逻辑,但使用不同的输入参数

@CsvSource

用于提供一组参数给参数化测试方法。使用逗号分隔的字符串表示多个参数,每个字符串代表一个测试案例。

@ParameterizedTest
@CsvSource({"1, 1, 2", "2, 3, 5", "5, 5, 10"})
void testAddition(int a, int b, int expectedSum) {
    int actualSum = a + b;
assertEquals(expectedSum, actualSum, "Sum of " + a + " and " + b + " should be " + expectedSum);
}
  • @ParameterizedTest 注解表示该方法是一个参数化测试方法。
  • @CsvSource 注解提供了一组参数,每一行代表一个测试案例。
    • 在这个示例中,提供了三组参数,每组参数包含两个整数和一个预期的结果。
  • 参数化测试方法 testAddition() 接受三个参数:两个整数和一个预期的结果。
    • 测试方法将对这些参数执行加法操作,并使用断言验证实际的结果是否与预期的结果相匹配。

@ValueSource

用于提供基本类型字符串类型参数逗号分隔多个参数,每个参数代表一个测试案例。

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testIsPositive(int number) {
//验证参数是否为正数
assertTrue(number > 0);
}

@MethodSource

用于指定一个方法提供参数给参数化测试方法。

@MethodSource 注解,可以将参数提供逻辑从测试类中抽取到一个单独的方法中,以提高代码的可读性和可维护性。

@ParameterizedTest
@MethodSource("stringProvider")
void testStringLength(String input, int expectedLength) {
assertEquals(expectedLength, input.length());
}
// 参数提供逻辑 抽取到 一个单独的方法
static Stream<Arguments> stringProvider() {
    return Stream.of(
            Arguments.of("apple", 5),
            Arguments.of("banana", 6),
            Arguments.of("orange", 6)
    );
}
  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java单元测试中的Mock是指在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来代替它,以便测试能够顺利进行。Mock可以模拟出一个对象的行为,使得测试人员可以在不依赖于真实对象的情况下进行测试。常用的Java Mock框架有Mockito和PowerMock等。下面是一个使用Mockito进行单元测试的例子: 假设我们有一个UserService类,其中有一个getUserById方法,该方法依赖于一个UserDao对象,我们可以使用Mockito来模拟UserDao对象的行为,从而测试getUserById方法的正确性。 ```java import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class UserServiceTest { @Mock private UserDao userDao; @InjectMocks private UserService userService; @Test public void testGetUserById() { User user = new User(); user.setId(1L); user.setName("Alice"); when(userDao.getUserById(1L)).thenReturn(user); assertEquals(user, userService.getUserById(1L)); } } ``` 在上面的例子中,我们使用了MockitoJUnitRunner来运行测试,使用@Mock注解来模拟UserDao对象,使用@InjectMocks注解来注入UserService对象。在testGetUserById方法中,我们使用when方法来指定当调用userDao.getUserById(1L)方法时,返回一个预设的User对象,然后使用assertEquals方法来判断userService.getUserById(1L)方法的返回值是否与预期相同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值