Primeiras aulas do curso Mocks em C#: testes de Integração com xUnit e Moq

Mocks em C#: testes de Integração com xUnit e Moq

Testes de Integração - Introdução

Sejam bem-vindos a mais um curso da plataforma Alura. Meu nome é Daniel Portugal e talvez vocês já me conheçam de outros cursos da plataforma dot.net. E nesse curso, eu quero apresentar para vocês testes de integração com C#, XUnit e Moq Framework.

Para contextualizar o teste de integração dentro da ideia de "testes", quero mostrar para vocês o seguinte: vocês já conheceram o teste de unidade usando o TDD e o Framework XUnit. Depois, vocês conheceram teste de interface do usuário usando Selenium Web Driver. E agora, eu quero mostrar para vocês os testes de integração, onde você precisa testar classes que dependem de outros componentes.

E, em geral, esses componentes são mais pesados. E o que você precisa fazer? Dando um spoiler, quando você encontra esse tipo de problema, você tem que testar uma classe que depende de um banco de dados, por exemplo, você substitui esse componente por uma versão mais leve.

Exatamente como você vê no cinema, onde se têm uma atriz ou um ator cuja utilização numa cena é arriscada, você substitui esse atriz ou ator por um dublê. Aqui também faremos isso. Nós vamos conhecer vários tipos de "dublês" para testes. E um desses tipos é o Mock. E como ferramental, nós vamos usar o XUnit, que já conhecemos bastante, com o Framework Moq.

Os exemplos que nós vamos usar para conhecer mais esse assunto são classes que dependem de bancos de dados usando Entity Framework Core e classes que também são controladores do Aspnet Core. O curso é muito rápido, fique tranquilo. Você vai fazer com um pé nas costas. Eu espero que você tenha ficado curioso. Se você ficou, venha comigo para o próximo vídeo.

Testes de Integração - Preparando o Ambiente

Vamos começar o nosso curso falando um pouco sobre o que vocês vão precisar para poder acompanhar o curso. Então, vocês vão ter um exercício onde irão baixar o projeto inicial. Antes tem que descompactar esse projeto inicial em algum lugar. Eu descompactei nessa pasta aqui. Abrirei ele com o Visual Studio 2019, mas também dá para usar no 2017, caso você não quiser baixar o de 2019.

Então, eu estou usando aqui o Visual Studio 2019, que é a versão para vocês. 16.2.1, no momento de gravação desse curso. E a a instalação que eu preciso desse Visual Studio é uma instalação bem básica. Precisa de desenvolvimento web, de desenvolvimento para plataforma dot.net Core e precisa também do C#, da linguagem C#.

Então, naquele Visual Studio installer, vocês vão poder marcar essas opções. Vamos falar um pouco do projeto. Vou fechar ele. E no projeto nós temos a solução, que tem duas pastas: uma pasta chamada de src, de source, e uma pasta chamada "testes", onde nós vamos colocar o projeto de teste.

Na pasta source, onde tem o nosso código de produção, nós vamos pegar isso aqui e fazer um deploy. Nós temos aqui quatro projetos: o primeiro projeto é justamente o Core, o núcleo da nossa aplicação, a aplicação que nós vamos desenvolver, na verdade, é uma parte muito pequena de uma aplicação de tarefas. Em outras palavras, de coisas a fazer.

E temos aqui tanto algumas classes de modelo, quanto algumas outras classes que eu já vou explicar qual é o propósito delas aqui. Estou chamando elas de comandos. Depois, nós temos o projeto que vai representar a infraestrutura que eu preciso para esse projeto, especificamente a parte de banco de dados.

Nós estamos usando o Entity Framework Core, e temos aqui uma abstração que é o repositório de tarefas, uma interface. Nós falaremos disso com calma, depois. Em seguida, nós temos a camada de serviços, o projeto chamado Services, que representa a camada de serviços.

E ela tem basicamente três classes que implementam e executam esses comandos aqui, os que foram definidos aqui na camada de núcleo. Então, agora eu posso falar um pouco dessas classes aqui. Essas três classes representam caso de uso, que eu tenho na minha aplicação.

Então, a minha aplicação tem três casos de uso: primeiro é cadastrar uma tarefa ou incluir uma tarefa. Segundo é gerenciar o prazo das tarefas. Vou abrir aqui a caixa para você ver. Essa classe representa o caso de uso onde você vai verificar se aquela tarefa já está atrasada ou não.

E tem um caso de uso que é um auxiliar, onde nós obtemos uma categoria, um objeto, uma instância de um objeto categoria através do seu identificador. Isso vai aparecer em outras situações e outros objetos também, mas, por enquanto, o que nós precisamos são esses três casos de uso aqui.

Esses comandos, essas classes que estão aqui, elas não são ainda a execução dos casos de uso. Essas classes representam apenas as informações que são necessárias para esse caso ser executado. Então quem executa esse caso de uso fica justamente aqui na camada de serviço.

Então aqui, repare que eu tenho um para um: uma classe cadastra a tarefa, handler, que é o manipulador, é o cara que lida e que executa esse caso de uso da tarefa. E esses outros dois, respectivamente, os outros dois.

E, por fim, nós temos a camada de interface do usuário que, nesse caso, é uma aplicação web, e essa aplicação web, por enquanto, ela tem o controlador home controller que foi gerada a partir da criação desse projeto no Visual Studio, eu não mexi nesse home controller, então eu nem sei o que é que tem aqui ainda, mas nós criamos um controlador de tarefas que apenas tem um endpoint responsável pelo cadastramento de atividades.

É ele que vai iniciar o caso de uso de cadastramento de tarefas. E ele é um controlador de api, o qual você vai chamar a barra tarefas usando o verbo post. Post/tarefas, passando algumas informações relativas a tarefas e ele vai executar esse caso de uso, se tudo der certo, ele vai dar ok.

Então, nós temos uma aplicação do início ao fim, mas apenas uma fatia dessa aplicação que nós já vamos usar para poder mostrar os conceitos que vamos aprender aqui no curso de testes de integração.

Então, reparem que nós temos vários projetos aqui e esses projetos representam camadas. E agora, nós queremos testar as camadas relativas à execução desse caso de uso e a execução também desse controlador, desse end point que está no controlador. Então, nós vamos ver como que fazemos para testar tanto um controlador de um api, quanto o controlador de uma classe que depende de outros objetos. No caso, do banco de dados, ali.

Testes de Integração - Testando recursos caros

Então, nós iremos começar criando um projeto de teste para testar o caso de uso "cadastra tarefa". Vou clicar com o botão direito aqui, adicionar, novo projeto. Eu quero um projeto do XUnit, próximo, o nome que eu vou dar vai ser "AluraCoisasAFazerTestes" e vou colocar ele dentro da pasta "testes".

Seleciono a pasta, criar. Ele já colocou uma classe de teste para nós, com o nome Space XUnit. Então, o que eu quero fazer é criar nossa tarefa. Como isso é feito nesse sistema aqui? Eu tenho que criar um comando e depois eu tenho que executar esse comando.

Esses dois são classes, cada um é um objeto. Vou ter que criar dois objetos: um para representar o comando e outro para representar o cara que vai executar esse comando. Lembre-se sempre, eu vou bater sempre nessa tecla nas nossas fases, arrange act e acerte.

Então, esse teste inicial é um teste bem básico, que é o seguinte: dado informações de tarefas, o título da tarefa, uma categoria, e o prazo para essa tarefa, eu quero que ela apareça no banco de dados. Então, olha só: o meu arranjo vai ser primeiro criar o comando que é new CadastraTarefa.

Esse cara aqui, se eu apertar o control, vai exigir que eu adicione uma referência ao projeto AluraCausasAFazerCore. Então, eu vou aproveitar e fazer isso. Observe que além de ter importado esse namespace aqui em cima da minha classe, ele também adicionou uma referência para o projeto Core.

Então, isso preenche automaticamente. Esse cara aqui, ele tem um construtor que exige três argumentos: o primeiro argumento é o título tarefa, então, Estudar XUnit. E a categoria, eu vou criar: New categoria. Vou empurrar também esse name space, e a categoria vai ser Estudo, é um Construtor que pede como argumento uma string com a descrição da categoria.

E, por fim, eu vou criar uma data que representa o prazo dessa tarefa e eu vou colocar aqui 31 de Dezembro de 2019. Quero quebrar automaticamente, para vocês poderem enxergar isso aqui.

Então eu criei o meu comando e agora eu vou criar o tratador desse comando, o handler. E esse cara é o CadastraTarefaHandler. Vou importar aqui novamente, ele vai importar o user e também vai colocar mais um projeto aqui como referência para o nosso teste.

E esse cara é um construtor que não precisa de argumento nenhum. Esse é meu arrange. Meu act é justamente o handler.execute. Aqui, eu vou executar e vou passar como argumento qual é o comando com suas informações para serem executados.

Então, esse é o primeiro teste que nós vamos fazer. Meu assert vai ser a tarefa foi cadastrada no banco de dados com o título Estudar XUnit, com a categoria estudo, com o prazo 31 de dezembro de 2019. Esse é o assert que eu quero fazer. Mas cadê o meu banco de dados? Como é que eu vou verificar isso aqui?

Vamos primeiro ver se nós conseguimos executar esse cara. E eu vou tentar fazer, só para dizer que vai passar esse teste. Assert true, passando true. Então, agora eu quero executar esse teste: botão direito, executar os testes, vai compilar todos e vai abrir o nosso gerenciador de testes. Abriu. E já abriu com erro.

Vamos ver o que é que está acontecendo aqui: Invade operation exception. Não foi definido um provider para o banco de dados. Na verdade, o ado.net exige que você configure um provider. Qual banco de dados você vai usar? SQL Server? Oracle? MySQL? Qual banco de dados? É o provider que vai dizer. E nós não temos na nossa aplicação, ainda, uma configuração para dizer: “você vai usar especificamente este banco de dados”, não tem isso.

Então, nós precisamos configurar isso, nosso teste falhou por conta disso. Outro problema que eu quero resolver aqui rapidamente é a nomenclatura. A nomenclatura não está me dizendo nada, aqui. Então, vou resolver essas duas coisas.

Então, a primeira coisa é acertar o nome. Vou renomear o arquivo onde tem a classe de teste. Nós vamos usar a nomenclatura já dos cursos anteriores que nós estamos fazendo de teste no C Sharp.

O nome da classe, respectivamente, do arquivo, vai ser o nome da classe sobre teste e o método que está sendo testado. Então, basta você olhar aqui, no act. Esse act vai ter que ser igual para todos os testes desta classe. Então a classe sob teste é CadastraTarefaHandler e o método sob teste é o execute.

Então o nosso sistema under, System under test, é o CadastraTarefaHandler Execute. Esse cara vai se transformar no nome da classe e no nome do no nosso arquivo de unidade de compilação. O Visual Studio 2019 não tem essa refatoração que o 2017 tem, que quando você muda lá, ele tenta mudar também o nome da classe. Ele não tem isso.

Então, agora eu mudei aqui na mão, e o nome do meu teste é DadaTarefaComInformacoesValidasDeveIncluirNoBanco. A princípio, é o nome que eu estou dando aqui, mas depois nós podemos refatorar e rever se realmente essa é o assert que nós estamos fazendo. Mas as informações são essas, as informações são válidas e eu quero que isso seja incluído no banco através desse comando aqui.

Não preciso nem executar. Quando eu já olhar aqui para o meu gerenciador de testes, ele já vai ter reconhecido essa mudança de nome. Primeira coisa legal.

Então agora eu vou configurar o provider, o meu provider aqui para o meu banco de dados. Então, onde é que eu vou configurar esse provider? Eu vou configurar esse provider na infraestrutura, no contexto. Aqui no meu contexto, eu vou dizer que, eu vou usar o banco de dados SQL Server.

Então aqui vou fazer um over ride ou um configure. E esse é um configure. Eu vou usar uma configuração chamada UseSQL Server, onde eu passo como argumento a string de conexão para esse SQL Server.

A string de conexão, é assim: Server. Vou usar aqui meu localdb mssqllocaldb; qual é o nome do banco de dados? Database vai ser igual a =dbtarefas. E como eu vou me conectar a esse banco de dados? Vou usar a mesma conta do Windows. TrustedConnection=true, então usa conexão. Confie na conexão que você já tem, como o Windows.

Então, eu estou agora configurando o meu provider. Vamos tentar executar novamente? Vou chegar aqui, executar testes selecionados, vou deixar aqui ele aberto, vamos ver o que é que vai acontecer. Está tentando executar e deu erro.

Qual é o erro que aconteceu? Vamos ver. Vou colocar aqui embaixo para vocês verem. E a mensagem é a seguinte: não foi possível abrir o banco de dados. O login failed. Na verdade, login failed para esse usuário, que é esse usuário aqui da minha máquina, essa credencial não foi aceita, mas na verdade esse banco de dados não existe.

Esse banco de dados aqui, se você olhar aqui para exibir, pesquisador, SQL Server, Object Explorer, aqui eu tenho uma visão de todos os bancos de dados que eu tenho acessíveis para minha máquina. E esse aqui é o banco de dados que eu estou usando, localdb, MYSQL, localdb. É o SQL express que vem com o Visual Studio.

Nos bancos de dados que eu tenho aqui, eu tenho um banco de dados daquele curso interior, leilões db, mas eu não tenho ainda o db tarefas. Então, eu terei que criar aqui esse banco de dados para, aí sim, poder realizar esse meu teste.

Mas pensa um pouco comigo aqui. Repare que eu estou tentando fazer um teste que exige um recurso da minha máquina. No caso da minha máquina, que é um banco de dados. Eu preciso ter, primeiro, o servidor, que é o SQL Server Express, que já está disponível.

Preciso agora ter o banco de dados instalado. E esse é um recurso que demora um pouco, não é uma coisa que rapidamente eu vou conseguir incluir. Então, esse teste que nós estamos fazendo aqui é um teste um pouco diferente dos daquele curso de teste de unidade que nós vimos.

É um teste que roda só em memória. Basicamente, nós fazemos os testes olhando apenas para essa camada de domínio. Nesse caso aqui, nosso teste depende de um recurso que é caro. E ele vai demorar para ser executado, acessado.

Então, quando nós temos esse tipo de situação, o que pode acontecer é que eu compartilhe esse recurso. Pode ser um banco de dados, pode ser um sistema de arquivos, pode ser um servidor web. Então, quando esse recurso é mais caro, o que acontece é que eu vou compartilhar esse recurso. Então vários desenvolvedores vão olhar para esse recurso, vão usar esse recurso.

E eu resolvo, por um lado, um problema de dividir um pouco esse custo, mas, por outro lado, agora eu vou ter o problema de saber se o que os dados que estão nesse banco de dados, estão, de fato, de forma que eu consiga fazer os meus testes com um cenário que eu gostaria.

Então, imagine que eu crie um cenário. Vou no banco de dados, faço essas inclusões para ele poder ser utilizado nesse teste especificamente, mas um outro testador está testando também naquele banco de dados e fez um teste de exclusão de tarefa e acabou excluindo meu cenário.

Se ele está sendo compartilhado, eu vou ter agora esse problema de conflito de cenários. Então, como que eu faço para resolver esse problema? Como eu consigo, ao mesmo tempo, testar, eu quero a execução deste comando, mas sem ter esses problemas do recurso que é caro ou então quando está compartilhado, haver conflito de interesses? Como eu faço para resolver isso?

Sobre o curso Mocks em C#: testes de Integração com xUnit e Moq

O curso Mocks em C#: testes de Integração com xUnit e Moq possui 185 minutos de vídeos, em um total de 55 atividades. Gostou? Conheça nossos outros cursos de .NET em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda .NET acessando integralmente esse e outros cursos, comece hoje!

Plus

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$85
à vista R$1.020
Matricule-se

Pro

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$120
à vista R$1.440
Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas