макетируйте все с помощью Mockito и проверьте, передается ли объект, полученный из одного макета, другому
Обычно вы извлекаете логику в методы, которые объясняют, что они делают.Если метод использует результат другого вызова метода, я бы посмеялся над вызовом этого метода и заставил бы его вернуть фиксированное значение.
делать интеграционные тесты с контекстом Spring, работающим
У вас обязательно должен быть тест, который проверяет ваш весенний контекст (вам может понадобиться только один)
пропустите тест контроллера, поскольку он не содержит бизнес-журнала
Ваш контроллер долженне содержат бизнес-логики, а скорее делегируют службе, которая выполняет некоторую работу.В Spring есть MockMvc, который позволяет вам тестировать один контроллер за раз (и издеваться над другими компонентами в контексте Spring).Это дает много возможностей для некоторых интересных и полезных тестов.
-
Я предпочитаю макетировать внешние системы.Мне нравится тестировать контроллер и логику в сервисе.Используя 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());
}
}
Пример теста, который является скорее интеграционным тестом(работает база данных in-mem):
@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());
}