Executando verificação de segurança...
1

Fiz um teste de integração na minha API Spring sem muita ajuda e preciso de feedback!

Olá comunidade!
Depois de 1 ano e meio de experiência com Java e sem auxílio direto ou assistir muitos vídeos (só um de 8 minutos 🫠), consegui implementar um teste de integração na minha API Spring. Eu estou trabalhando em um desafio estilo PicPay simplificado, e o projeto está quase finalizado. Agora estou na fase de escrever testes para garantir que tudo funcione direitinho.

A real é que não sei o quanto do que fiz está certo ou errado. Por isso, queria muito o feedback da comunidade! Vou compartilhar um dos testes que escrevi para validar a lógica de transferência de dinheiro na API. Aqui vai o código:

Controller

@SpringBootTest
@AutoConfigureJsonTesters
@AutoConfigureMockMvc
class ControllerTest {
    // Constantes para teste
    final BigDecimal AMOUNT_100 = new BigDecimal("100.00");
    final BigDecimal AMOUNT_0 = new BigDecimal("0.00");

    @Autowired
    private TransferMoneyTestScenario testScenario;

    @Autowired
    private CreateUserTestScenario userTestScenario;

    @Autowired
    private MockMvc mvc;

    @Test
    @DisplayName("Merchant cant do it transfer money.")
    void should_not_be_possible_merchant_user_transfer_money_to_common_user() throws Exception {
        // Given
        var commonUserResp = userTestScenario.createCommonUser();
        var merchantUserResp = userTestScenario.createMerchantUser();
        var commonId = userTestScenario.getIdFromResponse(commonUserResp);
        var merchantId = userTestScenario.getIdFromResponse(merchantUserResp);
        userTestScenario.updateBalance(commonId);
        userTestScenario.updateBalance(merchantId);
        testScenario.paymentAllowedByAuthorizer(true);

        // When
        var response = testScenario.executeTransferMoneyRequest(
                AMOUNT_100, merchantId, commonId
        );

        // Then
        var expectedResponse = testScenario
                .expectedErrorResponse(
                "Bad Request",
                "Comerciantes não estão autorizados fazer transferência."
                );
        assertThat(response.getStatus()).isEqualTo(400);
        assertThat(response.getContentAsString()).isEqualTo(expectedResponse);

        userTestScenario.deleteUserAndWallet(commonId);
        userTestScenario.deleteUserAndWallet(merchantId);
    }
}

Criei duas classes para abstrair a parte considera "feia" dos testes para não confundir quem está lendo; o Java já é meio verboso, deixar tudo junto deixaria o código bem dificil de ler

TransferMoneyTestScenario

@Component
public class TransferMoneyTestScenario {

    @MockBean
    private AuthorizationClient authorizationClient;

    @Autowired
    private MockMvc mvc;

    @Autowired
    private JacksonTester<TransferMoneyRequest> transferMoneyJson;

    public void paymentAllowedByAuthorizer(Boolean value) {
        var data = new Data(value);
        if(value) {
            var authorizedResponse = new Authorize("sucess", data);
            Mockito.when(authorizationClient.execute()).thenReturn(authorizedResponse);
        }
        var authorizedResponse = new Authorize("fail", data);
        Mockito.when(authorizationClient.execute()).thenReturn(authorizedResponse);
    }

    public MockHttpServletResponse executeTransferMoneyRequest(
            BigDecimal value, Integer payerId, Integer payeeId) throws Exception
        {
        var request = new TransferMoneyRequest(value, payerId, payeeId);
        return mvc.perform(post("/v1/transfer")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(transferMoneyJson.write(request).getJson()))
                        .andReturn()
                        .getResponse();
    }

    public String expectedErrorResponse(
            String reasonPhrase, String expectedMessage) throws JsonProcessingException
    {
        var errorMessage = new RestErrorMessage(
                reasonPhrase,
                expectedMessage);

        var objectMapper = new ObjectMapper();
        return objectMapper.writeValueAsString(errorMessage);
    }
}

CreateUserTestScenario

@Component
public class CreateUserTestScenario {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private JacksonTester<CreateUserData> createUserJson;

    @Autowired
    private UserRepositoryTest userRepository;

    @Autowired
    private WalletRepositoryTest walletRepository;

    public MockHttpServletResponse createCommonUser() throws Exception {
        var request = new CreateUserData("CommonUser",
                "019.327.760-36",
                "[email protected]",
                "123"
        );
        return mvc.perform(post("/v1/user")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(createUserJson.write(request).getJson()))
                .andReturn()
                .getResponse();
    }

    public MockHttpServletResponse createMerchantUser() throws Exception {
        var request = new CreateUserData("MerchantUser",
                "43.674.835/0001-30",
                "[email protected]",
                "123"
        );
        return mvc.perform(post("/v1/user")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(createUserJson.write(request).getJson()))
                .andReturn()
                .getResponse();
    }

    public Integer getIdFromResponse(MockHttpServletResponse response) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        ResponseUserData responseData = objectMapper.readValue(response.getContentAsString(), ResponseUserData.class);
        return responseData.getCreateUserResponse().id();
    }

    public void deleteUserAndWallet(Integer id) {
        walletRepository.deleteByUserId(id);
        userRepository.deleteByUserId(id);
    }

    public void updateBalance(Integer id) {
        walletRepository.setBalance(id);
    }
}

Dúvidas

  1. Arquitetura dos testes: Faz sentido o que fiz com os cenários (CreateUserTestScenario e TransferMoneyTestScenario)?
  2. Boas práticas: Alguma sugestão para melhorar a clareza ou estrutura do teste?

🎄 Boas festas pra vcs, valeus! 🎄

Carregando publicação patrocinada...