Testes unit%C3%A1rios - ifspcodelab/gestao-estagios-backend GitHub Wiki
Os testes unitários conferem se as pequenas partes de códigos em um projeto estão funcionando da maneira esperada, como os métodos presentes nas classes. Lembrando que deve ser testados os métodos de forma individual, sem fazer a integração entre eles.
Automatizar a verificação da consistência de um programa, que muitas vezes pode ser demorado e bastante custoso para um projeto, além de possibilitar a diminuição de ocorrências de erros em um sistema.
Frameworks Mockito e JUnit, além da biblioteca AssertJ.
Um framework Java que ajuda na realização de testes. Ele é muito importante pois simula os métodos e as instâncias das classes. Essa simulação é chamada de mock, que pode ser traduzido como "zombaria", é um nome interessante, pois realmente é o que acontece, quando se utiliza o mock para instanciar uma classe, ela "pensa" que seus métodos realmente foram chamados, o que na realidade não acontece.
-
Mock: cria uma instancia da classe de forma "mockada", como foi dito acima, será possível chamar os métodos, mas eles não serão invocados de maneira real. Exemplo: na classe CampusServiceImpl há uma dependência da classe CampusRepository, portanto na classe de testes do service, será necessário usar a anotação @Mock, para simular a instância da classe.
@Mock private CampusRepository campusRepository;
-
InjectMocks: muitas vezes as classes terão dependências, para sinaliza-las é necessário usar a anotação
@injectMocks
, dessa forma na classe que utilizar essa anotação será injetada as dependências anotadas com o@Mock
.@Mock private CampusRepository campusRepository; @InjectMocks private CampusServiceImpl campusService;
-
Verify: verifica se teve ou não alguma interação com os métodos implementados, além disso é possível verificar quantas vezes a operação ocorreu.
verify(campusRepository, times(1)).save(any(Campus.class));
Verifica se o método save foi chamado pelo menos uma vez com qualquer objeto da classe Campus.
-
When: utilizado para configurar o que acontece na chamada de um método, como o seu retorno.
when(campusRepository.existsByAbbreviation(any(String.class))).thenReturn(true);
Quando o método existsByAbbreviation da classe CampusRepository, passando como argumento qualquer valor da classe String for chamado, ele retornará o valor true.
Um framework Java, assim como o Mockito, visa contribuir para a execução de testes unitários. Com ele é possível automatizar os processos de testagem de todos os testes quando uma nova versão estável do sistema for lançada, ou até mesmo a cada commit realizado, garantindo assim, a estabilidade e integridade do sistema após novas mudanças.
- @ExtendWith: determina extensões a serem utilizadas dentro da classe de testes
@ExtendWith(MockitoExtension.class)
public class CampusServiceTest {}
- @Test: determina que será um método de teste
@Test
public void createCampus() {}
- @ParameterizedTest: com essa anotação é possível rodar os testes múltiplas vezes com valores diferente**
- @ValueSource: utilizado em conjunto com o @ParameterizedTest, com ele é possível determinar um array de valores a serem testados.
@ParameterizedTest
@ValueSource(ints = {0, -2})
public void testSetLadoDoesNotAssignValueWhenLadoEqualsOrLessThanZero(int lado) {
assertThrows(IllegalArgumentException.class, () -> new Quadrado(lado));
}
- @BeforeEach: determina que o método devera ser executado antes de cada @Test ou @ParemeterizedTest
@BeforeEach
public void setUp() {
campusService = new CampusServiceImpl(campusRepository);
campusService.setCityService(cityService);
campusService.setDepartmentService(departmentService);
}
- assertThat: utilizado para comparar objetos, normalmente vem acompanhado de outros métodos, como isEqualsTo, isTrue.
- isEqualTo: verifica se dois valores são iguais.
assertThat(campusFound.getId()).isEqualTo(campus.getId());
- isTrue: verifica se o valor é verdadeiro.
assertThat(result).isTrue();
- isFalse: verifica se o valor é falso.
assertThat(result).isFalse();
- isNotNull: verifica se um objeto não é nulo.
assertThat(campusFound).isNotNull();
- assertThatThrownBy: verifica se um método chama uma exceção.
- isInstanceOf: utilizado em conjunto com o assertThatThrownBy para verificar qual é a exceção lançada.
assertThatThrownBy(() -> campusService.create(sampleCampusCreateDto(campus)))
.isInstanceOf(CampusAlreadyExistsByEmailException.class);
Devem ser criados testes para todos os possíveis comportamentos do método, como quando ele realiza a ação corretamente, lança uma exceção, etc.
Primeiro, é necessário configurar a classe de teste para que os testes possam ser executados com o Mockito. Isso pode ser feito ao adicionar a anotação @RunWith
referenciando a classe MockitoJUnitRunner.class
na classe de teste. Veja o exemplo abaixo:
@ExtendWith(MockitoExtension.class)
public class CampusServiceTest
Na sequência, é necessário mockar as classes que são as dependências da que será testada. Para tanto, basta adicionar a anotação @Mock
, tal como é mostrado a seguir:
@Mock
private CampusRepository campusRepository;
@Mock
private CityService cityService;
@Mock
private DepartmentService departmentService;
Essas classes foram mockadas por conta de serem as dependências da classe CampusServiceImpl
, o que pode ser observado a seguir:
@Autowired
public void setCityService(CityService cityService) {
this.cityService = cityService;
}
@Autowired
public void setDepartmentService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
@Autowired
public void setCampusRepository(CampusRepository campusRepository) {
this.campusRepository = campusRepository;
}
Depois é necessário construir os testes de fato. Para tanto, basta adicionar a anotação @Test
no método de teste. Veja um exemplo a seguir:
@Test
public void findAllByStatus(){
State state = StateFactoryUtils.sampleState();
City city = CityFactoryUtils.sampleCity(state);
Campus campus = CampusFactoryUtils.sampleCampus(city);
when(campusRepository.findAllByStatus(any(EntityStatus.class))).thenReturn(List.of(campus));
List<Campus> campusFound = campusService.findAllByStatus(campus.getStatus());
assertThat(campusFound).hasSize(1);
}
No teste acima é criado o objeto campus
, sendo que o mesmo estará contido em uma lista retornada pelo método findAllByStatus
quando este receber um EntityStatus
qualquer. Observe que o comportamento do objeto mockado está sendo definido pelo método when
. Além disso, o campus obtido na chamada do método findAllByStatus
, que será apenas o campus criado anteriormente, será colocado em uma lista, a qual sofrerá uma verificação se possui o tamanho especificado.
Uma boa forma de escrever os testes de unidade é seguir o padrão AAA. Nesse padrão, o teste unitário deve seguir três etapas: Arrange (Preparar o teste), Act (Rodar o teste) e Assert (Verificar as asserções).
-
Na primeira etapa (Arrange) é feita a preparação de tudo que é necessário para que o teste possa ser executado. Então é nesse momento em que são simulados os comportamentos de um mock, inicializados objetos, declaradas as variáveis que serão passadas como parâmetros para o método a ser testado, etc.
-
Na segunda etapa (Act) é realizada a execução do método a ser testado, sendo passado para o mesmo as variáveis e objetos definidos anteriormente.
-
Na última etapa (Assert) é verificado se a operação realizada na etapa anterior surtiu o resultado esperado por meio dos asserts.
No Arrange, são construídos os objetos state
, city
e campus
e é configurado o comportamento do mock CampusRepository
para que o método findAll
do service funcione corretamente. No Act, o método a ser testado é executado e o seu resultado é colocado na lista de campus chamada campuses
. No Assert, é verificado se a lista de campus possui o tamanho especificado.
@Test
public void findAll() {
//Arrange
State state = StateFactoryUtils.sampleState();
City city = CityFactoryUtils.sampleCity(state);
Campus campus = CampusFactoryUtils.sampleCampus(city);
when(campusRepository.findAll()).thenReturn(List.of(campus));
//Act
List<Campus> campuses = campusService.findAll();
//Assert
assertThat(campuses).hasSize(1);
}
- https://inside.contabilizei.com.br/conceitos-basicos-sobre-mockito-73b931ce0c2c
- https://dev.to/daienelima/mockito-como-utilizar-de-maneira-simples-4h86
- https://medium.com/cwi-software/testando-seu-c%C3%B3digo-java-com-o-mockito-framework-8bea7287460a
- https://www.devmedia.com.br/junit-tutorial/1432
- https://mari-azevedo.medium.com/qualidade-e-junit-introduzindo-automatiza%C3%A7%C3%A3o-de-testes-unit%C3%A1rios-do-seu-software-java-no-dia-a-dia-849611de5574
- https://medium.com/@alamonunes/teste-unit%C3%A1rio-e-o-padr%C3%A3o-aaa-arrange-act-assert-cb81d587368a
- https://junit.org/junit5/docs/current/user-guide/#overview
- https://www.baeldung.com/introduction-to-assertj