我在Spring Boot
中浏览了与测试相关的各种在线教程,并对测试的引用方式感到困惑。
有些文章将使用@WebMvcTest
注释的控制器测试称为Unit Test
,而另一些将其称为Integration Test
。不知道哪一个是正确的。
相同的问题适用于使用@DataJpaTest
的存储库层测试。
我已经在我的应用程序中编写了以下两个测试,一个用于控制器,另一个用于存储库。
在底部,我对这两个都有一些疑问。请指导。
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
是确定测试类型(Unit
还是Integration
)还是在测试中使用@MockBean
确定吗?UserControllerTest.java
是单元测试,我们在这里使用userRepository
模拟@MockBean private UserRepository userRepository
依赖关系,而在UserRepositoryTest.java
中使用@Autowired private UserRepository userRepository
自动装配。为什么?? 答案 0 :(得分:7)
为什么需要弹簧来进行单元测试?您只能使用Mockito来这样做,而无需启动spring上下文。这里对此进行了详细解释和讨论:https://reflectoring.io/unit-testing-spring-boot/
在使用@MockBean时,这也让我感到困惑!是将其视为单元测试还是集成测试? 我认为,即使我们使用的是模拟bean,但我们仍在spring上下文中运行,对我而言,这是一个集成测试(因为单元测试不需要在其中运行任何spring上下文)。布兰登提到的同一站点认为@MockBean是集成测试https://www.baeldung.com/java-spring-mockito-mock-mockbean。
来自布兰登的回复:“集成测试不应包含任何模拟,并且两种测试都应单独运行。”
如果您要测试从控制器一直到DB的api,但又要排除其他系统(如kafka或外部微服务)怎么办?您将如何实现?您肯定需要@MockBean。这是一个集成测试,即使它具有模拟的bean。
总结(根据我的经验以及几天来搜索和阅读大量矛盾信息后得出的结论)。这是我的意见:
我认为最令人困惑的部分是仅在测试api层时 使用spring作为问题中的UserControllerTest (我 就是说调用api并确保它返回正确的 状态代码和响应格式)。那被认为是单元测试还是 整合测试?它不是单元,因为单元测试不需要弹簧 要在其中运行的上下文。实际上是介于单元和 集成测试。该资料很好地解释了这个概念 https://blog.marcnuri.com/mockmvc-spring-mvc-framework/(更具体地说是MockMvc独立设置),我认为, 然后返回到在哪里进行这些测试的团队(在单元中 测试文件夹,在集成测试文件夹中,在另一个文件夹中?) 另外,还需要使用良好的命名约定来避免任何 与纯单元测试或相同的纯集成测试混淆 类。从我所看到的,大多数团队都考虑这些单元测试,但是我 不确定这是否是最佳做法!
//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());
}
}
希望有帮助,请告诉我是否有更好的意见,因为我为此付出了很多努力:)
答案 1 :(得分:0)
使用Spring Boot进行单元测试和集成测试之间的主要区别在于,单元测试可以独立运行,而集成测试将在执行开始之前引导Spring上下文。
要单独运行,需要根据要测试的控制器模拟依赖项。这样,您就可以端对端地测试非常具体的测试用例,而不必担心数据库或服务的开销。因此,使用注释@MockBean。
因此,集成测试着重于集成应用程序的不同层,例如数据库。大多数人都使用内存数据库(例如H2)来测试其存储库。集成测试不应包含任何模拟,并且两种测试都应单独运行。