[MÚSICA] [MÚSICA] Olá a todos, meu nome é Eduardo Guerra e essa daqui é a caveira Tomei Todas, que vai estar participando dessa aula aqui com a gente e esse é o curso de Desenvolvimento de Software Guiado por Testes. Hoje vamos estar fazendo uma pergunta aí, que já ecoou os principais teatros, talvez não dessa forma, do mundo certo, que seria aí: Mockar ou não mockar? Eis a questão! Certo. Então, essa é uma questão que muita gente me faz. A gente tem que mockar ou não mockar? Que situações eu devo criar o mock no meu texto? São todas as situações que eu tenho alí uma dependência que eu tenho que criar o mock? Então, nessa aula a gente vai pegar algumas situações e aí vamos fazer a pergunta aqui, para a nossa amiga, mockar ou não mockar? E aí vamos ver aí cada situação o que é que seria mais adequado fazer para quando você estiver fazendo TDD você poder decidir melhor se você deve mockar, e até mesmo como você deve mockar aquela dependência. Então vamos ver aí o primeiro questionamento, se eu tenho uma dependência que lida com recursos externos, que são difíceis de testar e que tem uma lógica complexa. O que eu eu devo fazer? Mockar ou não mockar? Então vamos ver: mockar. Então esse caso, é caso perfeito para a gente mockar a nossa classe. Então, porquê mockar? Primeiro: esses recursos externos, principalmente se for acesso a redes, acesso a arquivos, ou acesso a bancos de dados, isso pode deixar o texto muito lento, e depois para você rodar sua Suite inteira às vezes com várias classes que estão fazendo esse acesso, isso pode tornar o texto bastante lento. Principalmente se você está fazendo isso, não na própria classe, mas talvez na classe que depende dela, então, esse é dos motivos pelo qual às vezes pode ser interessante você estar criando o mock. Outra coisa. Pode ser complicado preparar o cenário nesses casos onde, por exemplo, uma lógica é mais complicada. Às vezes ele faz cálculo complicado e você só precisa saber, esse cara precisa retornar 10, é o que eu preciso aqui para minha classe, mas não, você tem que ir lá e pensar todos os parâmetros que você tem que passar para aquela classe que faz aquele cálculo ultracomplicado para que ela retorne 10, então com o mock, você simplesmente fala: mock retorna 10 aí para o nosso amigo, para ele poder fazer o teste. A mesma coisa, por exemplo, para mandar e-mail, para uma classe que depende de outra que faz uma leitura de arquivo, o que interessa é o que ela vai retornar para você e não a leitura do arquivo si. Então tudo isso acaba dificultando essa questão do teste. Outro motivo que a gente tem para mockar é que nesse caso, por exemplo, você vai ter que interagir com arquivo para poder colocar o arquivo que a dependência precisa, ou você vai ter que interagir com servidor de e-mail para verificar se a dependência mandou e-mail. Então isso daí acaba acoplando o teste com essas APIs de mandar e-mail, de acessar arquivos, que é o que está sendo usado lá baixo e que às vezes não tem a ver com a classe mesmo que você quer desenvolver. Então isso aí também é motivo interessante para você mockar, porque se você não mockar, você vai acabar, seu teste vai acabar acoplado com essas APIs de fazer essas tarefas periféricas que não são relacionadas à sua classe si, mas sim com a dependência delas. Então vamos para a próxima, a próxima questão. Essa é uma pegunta que escuto bastante, muita gente vêm me questionar, se deve mockar diretamente uma classe, por exemplo uma JDK do Java ou de algum framework ou API. Eu tenho que mockar a classe do JDBC que acessa o banco de dados? Ou eu tenho que mockar a classe do frame, que é aqui que eu estou chamando. Então, toda e todas, mockar ou não mockar? Nesse caso, não mock. Mas eu não digo para não mockar nada, eu estou falando não mock esta classe. Ao invés disso, faça o seguinte: você pega a classe que você está desenvolvendo, você vai ter alí uma classe intermediária, tá que vai estar encapsulando essa API nativa. Então por exemplo, ao invés de você estar mockando aquela API nativa, você vai estar mockando essa classe que está encapsulando. E aí vamos ver, só para dar exemplo mais concreto, imagina que sua classe use diretamente uma classe que crie arquivo. Então ao invés de mockar a classe do Java, do JDK, que realmente cria aquele arquivo, eu vou criar uma classe que ela sim vai interagir com essa classe do JDK, que vai criar esse arquivo. Então eu vou criar uma classe intermediária, e aí eu vou criar mock dela, e não da classe do framework e etc. Então primeiro uma coisa. Porque não mockar essa API nativa? Primeiro, ela pode ter muitos detalhes. Lembra que é uma classe que não foi feita para sua aplicação, ela foi feita para todas as aplicações que quiserem usar aquilo. Então talvez aquela classe vai ter muitos métodos que você não precisa, que você nem sabe o que faz, e nem precisa saber. Aquela classe pode ser complicada, pode ser complicada de instanciar, pode não ter boas abstrações, então essa classe pode ter muitos detalhes desnecessários para você. Às vezes você precisa que ela faça uma coisa mas você tem que chamar 5 métodos para isso. Porque? Porque você tem que configurar uma série de coisas. Como é que você vai fazer tudo isso mock? É possível? É, mas vai ser mock muito mais complicado do que simplesmente se você tivesse método Faz Isso, aí você fala: método, ele tem que te chamar com isso e você retorna aquele outro negócio. Até mesmo os tipos de retorno dessas classes, para você simular com mock podem ser bem complicados, às vezes envolve até mais de uma classe. Às vezes você tem que chamar uma classe que cria outra, que essa sim você vai chamar métodos, aí você tem que criar outra para estar passando para ela. Tudo isso podem ser fatores que podem complicar você mockar diretamente a API nativa. Então, porque criar a classe que encapsula? Primeira coisa, essa classe que encapsula ela vai implementar diretamente o método que a sua classe precisa. Então se a sua classe precisa de enviar e-mail, essa classe vai ter lá: enviar e-mail. Ela não vai ter 7 destinatários, 7 não sei o que, configura o servidor de não sei do que. Ela não vai ter nada disso. Ela simplesmente vai ter o envia e-mail. Então ela vai ter, ela vai se encaixar perfeitamente com as necessidades. Isso aí no teste vai ficar muito, mas muito mais claro. E benefício que a gente acaba colhendo disso daí, é que a gente desacopla essa classe principal dessa API específica. Então vai estar desacoplando a classe que eu estou desenvolvendo, por exemplo, dessa API de e-mail. Então se, por exemplo, como eu tenho essa classe que encapsula o acesso à essa API de e-mail, se amanhã eu achar uma API mais eficiente, ou que se integra melhor com a minha infraestrutura, eu não preciso alterar a minha classe principal e simplesmente essa classe, cuja função é interagir com a API de e-mail para prover as funcionalidade na medida que a minha classe precisa. Então esse desacoplamento também é benefício que a gente ganha do mock. De uma certa forma tornar o teste mais fácil, tornar o teste mais simples, está facilitando está melhorando o design da própria aplicação. Vamos para a próxima, para o próximo questionamento, o próximo cenário. Então, às vezes a gente cria classes que tem aquelas coisas internas, onde você às vezes cria uma classezinha auxiliar, mas é aquela coisa que não aparece para os clientes e nem deve aparecer para os clientes. Então nesse caso, mockar ou não mockar? Nesse caso, eu não devo mockar. É uma classe interna, eu vou enxergar minha classe só a partir dali. Se ela não se encaixar naquelas questões de dificultar muito o teste, de depender de recursos externos, de ter uma lógica extremamente complicada, se ela é simplesmente uma solução interna alí na minha classe, não é necessário mockar. Então a primeira coisa é que o teste vai acabar ficando acoplado nessa solução interna da classe, tornando essa solução difícil de ser alterado. Então se depois: Eu criei aqui uma classe interna com tal característica. Se depois eu quiser mexer ali, trocar aquela classe interna por uma outra ou até mudar o formato como o meu teste, se ele estiver mockando aquela classe, isso vai gerar uma complicação muito grande, que aí acaba tornando até difícil de estar alterando e refatorando, e o objetivo não é esse. [SEM_ÁUDIO] Outra coisa, outro motivo porque não mockar, é porque como a minha solução interna vai estar ligada ao meu teste, por causa do mock, vai ser muito mais difícil estar refatorando e se eu quiser refatorar, eu vou ter que mexer, não só na minha classe mas também no teste. E o ideal, como a gente viu ali no chapéu do TDD é que no momento que eu estiver refatorando, o meu teste esteja bem estável. Então esse fato de você ter a solução interna ligada diretamente ao teste isso daí acaba dificultando, então é mais motivo pelo qual eu não devo mockar. E outra coisa, aquela solução interna, eu vou estar mockando ela, eu vou estar expondo ela na API externa da classe às vezes sem necessidade, é uma coisa que poderia ficar presa. Pode ser que você esteja pouco na dúvida agora. Poxa mas você falou que se for difícil, que eu posso ter uma solução interna, que é difícil. Então é aquela decisão que você tem que tomar na hora que você está fazendo TDD, na hora que você está fazendo o seu design, de qual é a estabilidade dessa API, o qual ela é importante para o sistema como todo, a interface dessa classe ou isso aqui é realmente uma coisa interna, que não interessa para o resto do sistema. Essa divisão, essa fronteira entre essas duas classes é importante ou não para mim. Então é essa a questão mockar ou não mockar? A sua dependência está pouco ligada à isso. É uma coisa interna, é uma solução local, isso aqui é importante no contexto do meu sistema como todo. Então eu vou mockar para que o cara alí tenha uma interface bem definida, essa questão do acoplamento do teste com a interface da sua dependência, está diretamente ligada ao fato de ela ser uma dependência estável ou não. Nosso último caso aqui, eu devo mockar uma dependência que pode receber uma classe com diferentes comportamentos? Às vezes a gente tem uma classe que falo assim: essa classe aqui vai ter esse down e acabou. Vai ter essa classe aqui que acessa esse arquivo, esse banco de dados e pronto. Às vezes eu posso ter uma classe, que eu falo assim: essa classe ela pode ter uma dependência que varia, que eu posso usar o polimorfismo para colocar várias classe alí. Nesse caso, esse tipo de dependência, mockar ou não mockar? Nesse caso, a resposta é mockar. Simplesmete porque você nem sabe qual dependência vai estar alí. Então a primeira coisa é, você pode usar o próprio mock para você projetar qual que é a API dessa dependência, qual que é a interface dessa dependência, que métodos essa dependência tem que ter? Então você fala assim olha, eu tenho aqui a minha classe principal e eu quero variar tal comportamento. Aí a partir dos testes você vai definindo quais são esses comportamentos que essa dependência precisa ter. Então o mock é até uma forma de você fazer o projeto dessa classe. Outro motivo para você mockar é que às vezes, se você pegasse uma classe específica para o teste ela pode não cobrir todos os comportamentos possíveis para aquela dependência. Vou dar exemplo simples. Imagine que eu tenha, eu coloque uma classe específica e aquela classe por exemplo nunca jogue uma exceção. Mas pode ser que outras classes que vamos supor, se eu tiver uma outra classe que acesse uma rede, ela pode gerar uma exceção, por exemplo, se a rede cair. E eu preciso que a minha classe esteja funcionando todos os casos e não só naqueles casos daquela classe específica. Porquê? Justamente pelo fato de eu poder usar polimorfismo e inserir várias classes diferentes no lugar daquela dependência. Então, às vezes, o mock você pode simular vários comportamentos diferentes, como exceções, tipos de retorno. Por exemplo, imagine uma classe que retorna número mas nunca retorna negativo. Pode ser que eu tenha uma dependência que vá retornar. Mas e aí, como a minha classe vai se comportar? Então o mock ele tem essa característica de permitir que você defina bem esses cenários de conseguir explorar todos eles no teste. Diferente se você estivesse usando uma implementação específica. E por fim, você pode usar o mock até para dividir as responsabilidades entre a classe e a dependência, ou seja, para você saber, ok, essa classe aqui ela precisa fazer isso, mas essa outra parte aqui quem me dá essa resposta é a dependência. Ou essa funcionalidade depende da resposta que a dependência me der. Então essa divisão de resposabilidades, alí, de uma forma mais fina de uma forma mais detalhada, ela também pode ser feita no teste, pode ser definida no teste, a partir do mock. Ou seja, esse cara vai me dar essa resposta, então isso aqui é responsabilidade da minha dependência. Aqui eu tenho que verificar a partir da resposta dele tenho esses casos aqui, então isso aqui é responsabilidade da minha classe. Então essa divisão mais fina entre responsabilidades, você também pode estar usando o mock, é mais motivo para você mockar nesse caso aí. Então eu espero que com isso a gente tenha falado pouquinho aí sobre mockar ou não mockar. Tivemos a participação da nossa amiga, Tomei Todas, que nos ajudou nessa questão teatral, mas eu quero que fique realmente esse recado, essa mensagem, que você simplesmente criar, não sair criando mock de todos os tipos de classes, ou deixar de criar mock, sair fazendo teste encapsulado de todas as classes. Para você realmente pensar nos motivos, eu apresentei aqui alguns cenários, que você cria o mock, você não cria o mock e às vezes você tem esses cenários misturados e você tem que pesar as coisas e realmente, criar ou não o mock, acaba sendo uma decisão de design, acaba sendo uma decisão importante quando você está fazendo o seu teste ou quando você está projetando o seu sistema. Que com TDD a gente projeta o sistema com o teste. Então, muito obrigado por assistir e espero que essa questão tenha ficado clara para vocês. [MÚSICA]