Como posso testar em unidade meu serviço web REST?

16

Eu sou novo no teste de unidade, tenho um método da web REST que apenas chama DB e preenche um DTO. O pseudo código é

public object GetCustomer(int id)
{
  CustomerDTO objCust = //get from DB
  return objCust;
}

Minha dúvida é como escrever testes para esses métodos e tipos de testes (Integração / Unidade) a serem incluídos. E para testes de unidade, ele precisa atingir o banco de dados. Se fosse e eu passar um ID de cliente e fizer poucas afirmações, os dados poderão mudar eventualmente resultando em falhas.

Acho que estou perdendo algo aqui, entendendo esses conceitos.

Ensolarado
fonte
5
No código que você postou, os itens a serem testados são: (1) Você pode chamar GetCustomer com um int como parâmetro. (2) Ele retorna um objeto CustomerDTO? (3) Esse objeto é preenchido do banco de dados conforme o esperado. (4) Um comportamento esperado ocorre se chamado com um int que não corresponde a um cliente válido? Nada disso tem a ver com REST ainda. Quando você estiver pronto para escrever o código que responde às solicitações RESTful, você escreverá testes para ele.
DaVido
@ DavidD: "Esse objeto é preenchido a partir do banco de dados conforme o esperado." decididamente não é um teste de unidade (em relação ao código do OP). Esse é um teste de integração.
Flater
Sim você está correto. Se eu pudesse voltar e alterar o comentário para mencionar que, em um teste de integração, você verificaria o componente DB e zombaria dele, eu faria essa edição, mas a janela de edição dos comentários seria de 5 minutos, e o comentário foi feito seis anos atrás. :)
DavidO 31/10/19

Respostas:

18

Durante o teste de unidade, não é esperado que você teste com um banco de dados, ou pelo menos não com um banco de dados que não tenha preparado para o teste de unidade. Testar com um banco de dados e, como tal, testar diferentes camadas do seu aplicativo ao mesmo tempo é geralmente visto como testes de integração . Com os testes de unidade, você deve testar apenas o que o seu método faz, o que ele retorna dependendo dos parâmetros diferentes e quando (ou não) deve falhar.

É esperado que, em seu método, você faça chamadas para métodos X de outras classes. Você não está testando esses métodos X , portanto, o que você precisa fazer é zombar desses métodos.

Suponho que você esteja escrevendo seu código em Java; nesse caso, você possui ótimas estruturas de zombaria, como o Mockito, que podem ser úteis para você. Se você usa ou não uma estrutura de simulação é sua escolha, vou apenas dizer que eles economizarão muito tempo e a que mencionei pelo menos não é realmente complicada.

Se você deseja apenas escrever seu próprio mock para experimentar, suponha que você tenha a seguinte CustomerRepositoryclasse:

public class CustomerRepository {
 public CustomerDTO getCustomer(int id) {
   ...
 }
}

Você pode escrever sua própria CustomerRepositoryclasse zombada e suja da seguinte maneira:

public class MockedCustomerRepository extends CustomerRepository {
 public boolean bThrowDatabaseException;
 public boolean bReturnNull;
 public boolean bReturnCustomerWrongId;
 public boolean bReturnCustomerWithId;
 public CustomerDTO getCustomer(int id) {
  if(bThrowDatabaseException) { 
    throw new DatabaseException("xxx"); 
  } else if(bReturnNull) { 
    return null; 
  } else if(bReturnCustomerWrongId) { 
    throw new CustomerNotExistException(id);
  } else if(bReturnCustomerWithId) { 
    return new CustomerDTO(id); 
  }
 }
}

Então, no seu caso de teste, você basicamente substitui sua instância "padrão" CustomerRepositorypor uma instância simulada que permitirá testar seu método para vários resultados de getCustomer:

public class CustomerRestTest {
  public void testGetCustomer_databaseFailure() {
    MockedCustomerRepository dto = new MockedCustomerRepository();
    dto.bThrowDataBaseException = true;
    yRestClass rest = new MyRestClass();
    rest.dto = dto;
    rest.getCustomer(0);
    // depending on what you do in your getCustomer method, you should check if you catched the exception, or let it pass, etc.. Make your assertions here

  public void testGetCustomer_customerNotExist() {
    // etc.
  }
}

Geralmente, todo método de teste deve testar apenas uma coisa, isso ajuda a manter seus testes pequenos e focados em uma tarefa.

Vou repetir :-) Escrever uma aula toda ridicularizada leva algum tempo, como você vê. Considere usar uma estrutura de zombaria, quanto menos se escreve código, menos erros se comete , certo? Zombar de um método que gera uma exceção ou retorna um determinado valor para um determinado parâmetro é um pedaço de bolo e leva 2 ou 3 linhas (com pelo menos mockito)

Espero que ajude a testar seu método REST.

Jalayn
fonte
4
Normalmente você não tem lógica nas suas classes de DTO, especialmente nenhuma que interaja com o seu armazenamento de dados.
JustAnotherUserYouMayKnowOrNot
1
Foi apenas um exemplo, mas você está absolutamente certo. Vou mudar os exemplos para que eles se adaptem melhor à teoria.
Jalayn