java之Spring Boot 中的单元测试或集成测试

Free-Thinker 阅读:42 2025-02-15 21:57:57 评论:0

我在 Spring Boot 中查看了与测试相关的各种在线教程并且对测试的引用方式感到困惑。

一些文章引用了使用 @WebMvcTest 的 Controller 测试注释为 Unit Test而有些人将其称为 Integration Test .不确定哪一个是正确的。

相同的问题适用于 @DataJpaTest 的存储库层测试.

我在我的应用程序中编写了以下两个测试,一个用于 Controller ,另一个用于存储库。

在底部,我对两者都有一些疑问。请指导。

UserControllerTest.java

@RunWith(SpringRunner.class) 
@WebMvcTest(UserController.class) 
public class UserControllerTest { 
 
    @Autowired 
    private MockMvc mockMvc; 
    @MockBean 
    private UserRepository userRepository; 
 
    @Test 
    public void signUp() throws Exception { 
        this.mockMvc.perform(get("/signup")).andExpect(status().isOk()); 
    } 
 
} 

UserRepositoryTest.java
@RunWith(SpringRunner.class) 
@DataJpaTest 
public class UserRepositoryTest { 
 
    @Autowired 
    private TestEntityManager entityManager; 
    @Autowired 
    private UserRepository userRepository; 
 
    @Test 
    public void whenFindByName_thenReturnEmployee() { 
        // given 
        User u = new User(); 
        u.setName("ab"); 
        u.setEmail("ab@cd.com"); 
        entityManager.persistAndFlush(u); 
        // when 
        Optional<User> user = userRepository.findById(1L); 
        // then 
        assertTrue(user.isPresent()); 
    } 
 
} 

我的问题是:
  • 是否批注@WebMvcTest, @DataJpaTest@SpringBootTest确定测试类型( UnitIntegration )还是使用 @MockBean在测试中,它决定了吗?
  • 假设 UserControllerTest.java是我们模拟的单元测试 userRepository此处依赖 @MockBean private UserRepository userRepository而在 UserRepositoryTest.java我们正在使用 @Autowired private UserRepository userRepository Autowiring 它.为什么 ??
  • 请您参考如下方法:

    为什么需要spring来做单元测试?您只能使用 Mockito 来执行此操作,而无需启动 spring 上下文。这在此处详细解释和讨论:https://reflectoring.io/unit-testing-spring-boot/

    在使用@MockBean 时,我也很困惑!这被认为是单元测试还是集成测试?
    在我看来,即使我们使用的是模拟 bean,但我们仍然在 spring 上下文中运行,对我来说这是一个集成测试(因为单元测试不需要任何 spring 上下文来运行)。 Brandon 提到的同一站点将 @MockBean 视为集成测试 https://www.baeldung.com/java-spring-mockito-mock-mockbean .

    Image from above site

    Brandon 回应:“集成测试不应该包含任何模拟,两种类型的测试都应该单独运行。”

    如果你想测试一个从 Controller 开始一直到数据库的 api,但又想排除其他系统(比如 kafka 或外部微服务)怎么办?你将如何实现这一目标?你肯定需要@MockBean。这是一个集成测试,即使它模拟了 bean。

    总而言之(根据我的经验以及在搜索和阅读了很多天的矛盾信息之后)。这是我的意见:

  • 我想说的是,尽可能不要使用 spring 进行单元测试,而只使用 Mockito 或其他不需要 spring 上下文的框架。例如,在为服务类编写测试以测试某些计算逻辑时,我们不需要 spring 上下文,这是一个 PURE 单元测试。
  • 我们仍然可以为 Controller 类编写 PURE 单元测试。我们可以通过调用 Controller 中的方法来做到这一点,然后断言这些方法做了预期的事情(例如,使用正确的参数调用正确的底层方法......等)。为服务类编写单元测试时的方式基本相同。 (如果以下类型的测试已经涵盖这些内容,也许不需要这些?)
  • 我们仍然可以在没有任何 spring 上下文的情况下为 api 编写纯单元测试。此描述 here .我试过了,它对我有用。我会把代码贴在帖子的最后。
  • 在 spring 上下文中运行测试时,这被认为是
    即使您使用@MockBean,也可以进行集成测试。这方面的一个例子:
    如果我们想从 Controller 开始测试一个 api 一直到
    数据库,但我们想排除其他系统(如 kafka、电子邮件或
    其他外部微服务)。我们将如何实现这一目标?我们
    绝对需要@MockBean。这是一个集成测试,即使它
    使用一些模拟 bean 。
  • 我认为最令人困惑的部分是仅在测试 api 层时 在问题中使用 spring 作为 UserControllerTest 确实 (一世
    意思是调用 api 并确保它返回正确的
    状态代码和响应格式)。这被认为是单元测试还是
    集成测试?它不是一个单元,因为单元测试不需要 spring
    要在其中运行的上下文。它实际上是介于 unit 和
    集成测试。这个来源很好地解释了这个概念
    https://blog.marcnuri.com/mockmvc-spring-mvc-framework/ (更具体地说是 MockMvc 独立设置)所以我认为,
    然后返回到团队在哪里放置这些测试(在单元中
    test 文件夹,在集成测试文件夹中,在一个单独的文件夹中?)
    还需要使用良好的命名约定来避免任何
    与纯单元测试或纯集成测试混淆
    类(class)。据我所知,大多数团队都会考虑这些单元测试,但我
    我不确定这是否是最佳做法!
    //unit test to call an api using MockMvc and mockito only 
    @RunWith(MockitoJUnitRunner.class) 
    public class UserControllerTest { 
     
    private MockMvc mockMvc; 
    @Mock 
    UserService userService; 
    @InjectMocks 
    UserController controllerUnderTest; 
     
    @Before 
    public void setup() { 
        MockitoAnnotations.initMocks(this); 
        mockMvc = MockMvcBuilders.standaloneSetup(controllerUnderTest).build(); 
    } 
     
    @Test 
    public void testGetUser() throws Exception { 
     
        //given: 
        when(userService.getUser(.......)).thenReturn(....); 
     
        //when: 
        String url = "http://localhost:8081/api/ ....your url"; 
     
        //then: 
        this.mockMvc.perform(get(url)).andDo(print()).andExpect(status().isOk()); 
    } 
    

    }

  • 希望有所帮助,如果有更好的意见,请告诉我,因为我为此苦苦挣扎:)


    标签:java
    声明

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    关注我们

    一个IT知识分享的公众号