在我的应用程序中,我有一个基于给定模式的控制器:
public class Controller {
@Autowired
Mapper mapper;
@Autowired
Service service;
public EntityDto create(EntityDto dto) {
Entity entity = mapper.mapToEntity(dto);
Entity saved = service.save(entity);
return mapper.mapToDto(saved);
}
什么是测试此类的好方法?我看到了几种可能性:
以上任何一项都可以吗?也许其他方式?
答案 0 :(得分:1)
我假设您使用的是Spring Boot应用程序,则可以按如下所示在测试包下编写测试类:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class TestController {
@Autowired
Controller controller;
@Test
public void test() {
fail("Not yet implemented");
}
@Test
public void testGroupAlert() throws EntityNotFoundException, Exception {
Entitydto dto = new Entitydto() //Initialize your Entitydto object
controller.create(dto);
}
答案 1 :(得分:0)
我最常看到的方法是:
答案 2 :(得分:0)
如果要进行出色的测试,唯一的方法是进行单元测试和集成测试。
仅在需要时才启动集成测试(例如:Maven可以识别测试是否为集成)。
如果想要弹性代码,则单元测试不能用任何东西代替。
执行此操作的一个好方法是,因为您猜测要使用模拟引擎。 (如Mockito)。
这样做的目的是真正以各种可能的方式控制类,而无需其他层的交互。
但是要小心!如果您在所有层和所有类上执行此操作,则将起作用。
如果您正在使用现有代码,请查看已完成的操作并尝试使用它并尽力而为。
请记住,一个好的测试不是涵盖最广泛的测试,而是涵盖了最好的一种测试。
答案 3 :(得分:0)
您的控制器没有业务逻辑,但是它接受并产生一些JSON(或其他数据),这些JSON将由其他服务(即前端)使用。
这就是为什么值得检查API合同的原因。
为此,您可以使用Spring Could Contract框架。
答案 4 :(得分:0)
用Mockito模拟所有内容,并检查是否将从一个模拟中检索到的对象传递给另一个
通常,您将逻辑提取到解释其功能的方法中。如果该方法使用另一个方法调用的结果,那么我将模拟该方法调用并使其返回固定值。
在运行Spring上下文的情况下进行集成测试
您当然应该有一个测试可以验证您的spring上下文(您可能只需要一个)
跳过控制器的测试,因为它不包含业务日志
您的控制器不应包含业务逻辑,而应委派给执行某些工作的服务。 Spring具有MockMvc,可让您一次测试一个控制器(并在spring上下文中模拟其他bean)。这为一些有趣且有用的测试提供了许多机会。
-
我更喜欢模拟外部系统。我喜欢测试服务中的控制器和逻辑。使用MockMvc,我还可以验证http响应。
假设我有一个三层应用程序:
Controller -> Service -> Repository (mock this one)
使用MockMvc进行示例测试:
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = {CategoryController.class})
public class CategoryControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private CategoryRepository repository; // mock database, but validate logic in the service-class
@Test
public void create_new_catgory() throws Exception {
var category = new Category("test");
given(repository.save(any())).willReturn(category);
mockMvc.perform(post("/category")
.content(toJson(new CategoryRequestDto("")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is2xxSuccessful())
.andExpect(content().json(toJson(category)));
verify(repository, times(1)).save(any());
}
}
更多关于集成测试(运行内存数据库)的测试示例:
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {ShoprApplication.class, TestConfig.class})
@Transactional
public class ProductControllerTest {
@Autowired TestRestTemplate template;
@Autowired EntityManagerFactory entityManagerFactory;
private TestEntityManager em;
@BeforeEach
public void configure() {
em = new TestEntityManager(entityManagerFactory);
}
@Test
public void createProduct() {
var response = template.postForEntity(
"/product",
new Product("Apples", 15.00, new Category("Fruit"), 6),
Long.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody() != null && response.getBody().intValue() > 0L);
var product = em.getEntityManager().find(Product.class, response.getBody());
assertNotNull(product);
assertEquals("Apples", product.getName());
}
答案 5 :(得分:0)
1&2
我认为您应该在所有层中使用模拟库测试所有类。甚至最琐碎的类也很好测试。
然后,您应该进行集成测试。
我认为,如果集成测试不需要任何外部系统,那么它们也可以一直运行。唯一的事情可以是时间。我没去过那些需要几分钟才能进行集成测试的项目。
内存数据库和集成测试库/框架(例如@SpringBootTest)非常适合集成测试。
我认为良好的测试可以进行很多重构。如果进行重构,那么集成测试不会中断太多。 JUnit测试可能会中断,但是我不认为这是问题。您应该始终拥有尽可能简单简洁的代码和测试。
答案 6 :(得分:0)
您最终会遇到Test Pyramid-很多快速的单元测试,没有那么多可以一起检查的高级测试,没有模拟框架。