Posts da Tag: Teste Unitário - Blog da TreinaWeb

C#

C# – Testando requisições com Flurl

No meu artigo passado, demostrei a facilidade do uso da biblioteca Flurl no consumo de dados de uma API. Entretanto o ponto de maior orgulho desta biblioteca é a facilidade em testar as requisições criadas com ela.

Testes de unidades em requisições HTTP

Testar classes que fazem requisições HTTP pode ser um ponto complexo do projeto. Ele precisa ser desenvolvido de forma que aceite um Mock ou fazer uso de uma API de testes.

Uma API de testes pode ser uma boa escolha, mas caso ocorra algo com a mesma, os testes do projeto irão falhar. Enquanto o problema com a API não for resolvido, estes testes não poderão ser realizados.

Então, o mais comum é o uso de Mock, que deve ser implementado de acordo com a biblioteca de requisições implementada, já que a classe HttpClient não pode ser “mockada”. Ela não define interfaces que facilitariam este processo.

Dentre as bibliotecas de requisição que permitem o uso de Mock, a Flurl é a que torna este processo o mais transparente e simples.

Definindo testes de unidade com Flurl

Para exemplificar, serão implementados testes de unidade no projeto apresentado no meu artigo anterior. Nele vimos a implementação do Flurl na camada repository do projeto, assim, os testes de unidade mostrados aqui serão realizados apenas nesta camada.

Os testes podem ser feito graças a classe HttpTest da biblioteca. Recomenda-se que ela seja declarada em um bloco using:

using (var httpTest = new HttpTest()) {
    // Realizar as requisições aqui
}

Desta forma, todas as requisições realizadas dentro deste bloco serão interceptadas pela classe e com isso, poderão ser “mockadas”:

public async Task TestListProducts()
{
    var repository = new ProductRepository();
    using (var httpTest = new HttpTest()) {
        // arrange
        httpTest.RespondWith("[{\"id\":\"12d3d23\",\"name\":\"Mouse\", \"quantity\":10, \"price\": 99.9}, {\"id\":\"213drwa3\",\"name\":\"Teclado\", \"quantity\":20, \"price\": 149.9}]");

        // act
        await repository.FindAll();

        // assert
        httpTest
            .ShouldHaveCalled("http://localhost:3002/api/products")
            .WithVerb(HttpMethod.Get);
    }
}

Acima, é definido o mock:

httpTest.RespondWith("[{\"id\":\"12d3d23\",\"name\":\"Mouse\", \"quantity\":10, \"price\": 99.9}, {\"id\":\"213drwa3\",\"name\":\"Teclado\", \"quantity\":20, \"price\": 149.9}]");

Ou seja, não importa qual requisição, será retornado este conteúdo.

Em seguida a requisição é realizada:

await repository.FindAll();

E é verificado se ela foi feita para a API via GET:

httpTest
    .ShouldHaveCalled("http://localhost:3002/api/products")
    .WithVerb(HttpMethod.Get);

Ao executar o teste, ele irá passar:

asciicast

Definindo critérios para as requisições interceptadas

No exemplo anterior todas as requisições realizadas serão interceptadas pela classe HttpTest. Entretanto, é possível refinar isso:

public async Task TestCreateProducts()
{
    var repository = new ProductRepository();
    using (var httpTest = new HttpTest()) {
        // arrange
        httpTest
                .ForCallsTo("http://localhost:3002/*", "https://api.com/*")
                .WithVerb(HttpMethod.Post)
                .RespondWith("[{\"id\":\"12d3d23\",\"name\":\"Mouse\", \"quantity\":10, \"price\": 99.9}", 201);

        var product = new Product {
            Name = "Mouse",
            Quantity = 10,
            Price = 99.9
        };

        // act
        await repository.Add(product);

        // assert
        httpTest
            .ShouldHaveCalled("*/api/products")
            .WithRequestBody("{\"Id\":*,\"Name\":\"Mouse\",\"Quantity\":10,\"Price\":99.9}")
            .WithVerb(HttpMethod.Post);
    }
}

Note que é definido as APIs que serão interceptadas e o verbo HTTP:

httpTest
        .ForCallsTo("*localhost:3002/*", "*api.*.com/*")
        .WithVerb(HttpMethod.Post)

Qualquer requisição que não se enquadre nestes critérios será ignorada pela HttpTest.

No assert, se verifica apenas o endpoint:

httpTest
    .ShouldHaveCalled("*/api/products")

Não é necessário informar o servidor, porque os aceitos já estão definidos no critério especificado. Também note que é utilizado curingas (*). Eles podem ser implementados nos parâmetros de todos os métodos da classe.

Caso o teste seja executado, este segundo também passará:

asciicast

Conclusão

Adicionar testes em um projeto é uma boa prática que todos devem adotar. Ao se trabalhar com requisições, este processo pode ser facilitado ao adotar a biblioteca Flurl. Assim, caso esteja trabalhando com requisições e necessite implementar testes, não deixe de verificar esta biblioteca.

Neste artigo não foram abordados todos os métodos da classe HttpTest. Como vários são úteis, não deixe de vê-los na documentação da mesma.

Então é isso, por hoje é só 🙂


Testes e Projetos

Importância dos testes de software na qualidade do sistema

Testes de software é um conjunto de processos com os quais se pretende validar um sistema ou aplicação, em momentos diferentes, para verificar seu correto funcionamento. Este tipo de teste cobre qualquer etapa do desenvolvimento do sistema, desde sua criação até a implantação. São uma série de procedimentos que visam encontrar possíveis bugs, reportar erros, identificar problemas de usabilidade, bem como assegurar que todos os requisitos solicitados pelo cliente sejam atendidos.

Os testadores de software devem validar o máximo de combinações que podem ser aplicadas no software. Eles mantêm um registro detalhado dos testes realizados e, depois de conclui-los, elaboram uma lista com os bugs identificados e possíveis sugestões para melhoria do sistema. Este relatório é feito para que os desenvolvedores e gerentes do projeto possam verifica-los e corrigi-los posteriormente.

Profissionais de teste identificam todos os possíveis riscos para o sistema ou aplicação, tais como: erros que podem ocorrer no software quando alguém está usando, problema de usabilidade ou falta de informação, instalação do software em diferentes tipos de sistemas, se o software atende aos requisitos do projeto, se o sistema funciona conforme o esperado, se a interface está de acordo, se atende ao uso pretendido em relação as expectativas do usuário, entre outros aspectos.

Teste de Software Intermediário
Curso de Teste de Software Intermediário
CONHEÇA O CURSO

Qual a importância dos testes de software na qualidade do sistema?

De acordo com a International Software Testing Qualifications Board (ISTQB), um selo internacional de qualidade para testadores de software, realizar estas validações é de suma importância pelos seguintes motivos:

  • Permite identificar erros durante as etapas de desenvolvimento;
  • Garante a confiança do usuário final e sua satisfação ao utilizar o software;
  • Permite assegurar a qualidade do produto e seu funcionamento correto;
  • É fundamental para manter a reputação do negócio no setor.

Entre seus objetivos específicos estão:

  • Verificar a integração adequada dos componentes;
  • Analisar se todos os requisitos foram implementados corretamente;
  • Garantir que os defeitos encontrados sejam corrigidos antes da implantação do software;
  • Reduzir custos de manutenção corretiva e retrabalho.

Considerando todos estes itens, podemos afirmar que os testes de software visam encontrar erros no sistema para que, posteriormente, eles sejam corrigidos e a qualidade do mesmo seja melhorada. Executar estas validações garante que todos estes pilares sejam atendidos e que a empresa de tecnologia mantenha um alto nível no mercado.

Tipos de testes

A lista de tipos de testes é extensa e os métodos podem variar de acordo com o objetivo estabelecido para o projeto. Abaixo comentaremos brevemente sobre os principais tipos de testes existentes:

  • Teste de Unidade: É utilizado para validar se um pedaço do código está funcionando corretamente. Uma unidade é a menor parte testável em um sistema;
  • Teste de Integração: É utilizado para verificar a integração correta entre os diferentes componentes, uma vez que já tenham sido testados em unidade, com o propósito de verificar se eles interagem corretamente por meio de suas interfaces;
  • Teste Operacional: É utilizado para assegurar que o sistema pode rodar por muito tempo sem apresentar problemas;
  • Teste Positivo-Negativo: É utilizado para assegurar que o sistema vai funcionar pelo caminho feliz de sua execução;
  • Teste de Regressão: É utilizado para testar o sistema sempre que algo for alterado, com o objetivo de verificar se não surgiram novos erros em componentes já analisados;
  • Teste de Caixa-Preta: É utilizado para verificar todas as entradas e saídas desejadas. É ignorado a estrutura interna do código, detalhes de implementação ou cenários de execução internos no software, focando apenas nos requisitos funcionais do sistema;
  • Teste Caixa-Branca: É utilizado para testar o código. Garante a análise de todos os caminhos independentes de cada módulo, programa ou método;
  • Teste Funcional: É utilizado para validar as funcionalidades, requisitos e regras de negócios;
  • Teste de Interface: É utilizado para verificar se a navegabilidade e os elementos da tela estão funcionando corretamente, bem como se atende melhor o usuário;
  • Teste de Performance: É utilizado para verificar se o tempo de resposta do sistema é o desejado;
  • Teste de Carga: É utilizado para analisar se o sistema vai funcionar como o esperado mesmo havendo uma quantidade grande de usuários simultâneos;
  • Teste de Volume: É utilizado para testar a quantidade de dados envolvidos;
  • Testes de Estresse: É utilizado para testar o sistema em situações inesperadas;
  • Testes de Configuração: É utilizado para verificar se o sistema vai funcionar em diferentes hardware e software;
  • Teste de Compatibilidade: É utilizado para verificar se o sistema funciona corretamente em diferentes navegadores e sistemas operacionais;
  • Testes de Instalação/Desinstalação: É utilizado para verificar se o sistema será instalado e desinstalado completamente, parcialmente, ou atualizado corretamente em diferentes sistemas operacionais;
  • Testes de Segurança: É utilizado para testar a segurança do sistema ou aplicação, usando diversos tipos de perfis e permissões.

Considerações finais

No desenvolvimento de software, os erros podem aparecer em qualquer etapa do ciclo de vida do projeto. Diante disso, o teste de software se torna essencial e não pode ser visto como uma atividade opcional, pois oferece os métodos e ferramentas necessárias para garantir a qualidade de qualquer desenvolvimento.

É preciso ter consciência da importância dos testes de software e do engajamento da equipe de qualidade em todas as fases de desenvolvimento do sistema ou aplicação, sem que isso seja considerado um prejuízo econômico no planejamento de um projeto.

Sem dúvida nenhuma, é muito melhor detectar os erros no momento certo, gerando tempo hábil para corrigi-los, do que detectá-los antes da entrega do produto ou de uma etapa importante de implementação. Se quiser saber mais sobre testes de software e a sua importância, consulte o curso de Teste de Software Intermediário da TreinaWeb.