É muito importante conhecer o ciclo de vida dos testes unitários no desenvolvimento de serviços com Spring Boot.
A biblioteca spring-boot-starter-test
do Spring traz consigo atualmente todos os recursos (ou quase todos) necessários para testes com JUnit na sua última versão.
Nos testes de componentes/beans de um projeto, é comum o uso das anotações @ExtendWith(MockitoExtension.class), @InjectMocks e @Mock.
@ExtendWith(MockitoExtension.class)
class TestTest {
@InjectMocks
private Test test;
@Mock
private LalaService service;
//testes abaixo
}
E é comum nos testes termos reaproveitamento de estados de objetos nos vários cenários em que os estados se repetem ou que modifiquem parcialmente.
@ExtendWith(MockitoExtension.class)
class TestTest {
@InjectMocks
private Test test;
@Mock
private LalaService service;
@Test
void shouldDoesNotThrow() {
final var person = buildValidPerson();
//restante do teste
}
@Test
void shouldThrow() {
final var person = buildValidPerson();
//restante do teste
}
static Person buildValidPerson() {
return new Person("João");
}
}
Evite usar métodos estáticos para a geração desses objetos reaproveitáveis. Utilize o @BeforeEach (que executa antes de cada teste unitário) e atributos nos testes que armazenem estes valores. Assim terá o mesmo resultado, mas utilizando o ciclo de vida do teste unitário da melhor forma.
@ExtendWith(MockitoExtension.class)
class TestTest {
@InjectMocks
private Test test;
@Mock
private LalaService service;
private Person person;
@BeforeEach
void setup() {
person = new Person("João");
}
@Test
void shouldDoesNotThrow() {
//restante do teste
}
@Test
void shouldThrow() {
//restante do teste
}
}
Uma das exceções de uso de métodos estáticos gerando massas são para testes parametrizados (@ParameterizedTest e @MethodSource). E mesmo assim, são para conjunto de objetos de estados diferentes, não se aplica a reaproveitamento de estados.
Além do @BeforeEach existe também o @AfterEach que, como o próprio nome diz, é após cada teste.
Utilizar o @BeforeEach faz com que o teste unitário, seja ele único ou múltiplo, obedeça o ciclo de vida default (que é por método, é possível configurar por classe, mas isso é papo para outro post) do JUnit.