Olá, sejam todos muito bem-vindos a mais uma aula. E na aula de hoje a gente vai dar continuidade aqui à implantação do hexagonal. E, bom, bora lá, né? A gente entendeu a anatomia dos casos de uso na última aula, agora está na hora de a gente extrair eles. Acho que a gente pode começar, por exemplo, extraindo o caso de uso do customer. a gente pode começar, por exemplo, extraindo o caso de uso do customer mas antes de começar a extrair esses casos de uso de customer e partner que são os mais fáceis, vamos dar uma olhadinha em como estão os testes é importante a gente ver os testes antes de sair fazendo essa mudança para garantir, por exemplo, que os testes funcionam que os testes estão cobrindo exatamente aquelas linhas, pelo menos. Então, deve obter um cliente por ID, não deve cadastrar um cliente com e-mail duplicado, não deve cadastrar um cliente com um ICPF duplicado, deve criar um cliente. Então, a gente vê que, de certa forma, os testes estão confiáveis aqui, né? Então já é um bom caminho. O que a gente vai fazer então? A gente pode, por exemplo, começar com o TDD. Vamos criar aqui, Alt Insert, um package chamado Application, tá? E eu vou criar só um dummy class aqui, para ele não atrapalhar o meu package aqui. Então eu vou criar um outro package chamado useCases. Dentro aqui de useCases, a gente vai começar a colocar os useCases. Então, createCustomer. Opa, createCustomer beleza, agora o que a gente pode fazer aqui? vamos brincar public void given vamos colocar tudo em português mesmo? ou melhor vamos ver como é que está aqui na verdade vamos ver como está o controller aqui test create vamos trazer isso aqui deve criar um cliente test teste create, fechou. Então, teste create e a gente coloca deve criar um cliente. Vamos colocar aqui um DTO, só que em vez de dar o DTO, a gente vai utilizar, por exemplo, o input do caso de uso. Então, vai ser algum tipo de input aqui esse input ele vai ser imutável e vai receber os parâmetros então em ordem aqui então e-mail cpf e-mail e o também. Beleza, é isso que a gente precisa. Create input. Beleza. Agora, o que é feito aqui? É feito uma chamada http e depois é comparado o resultado com o que a gente tem lá. Então vamos lá, o que a gente pode fazer aqui? Vamos colocar aqui. Só que antes, o que eu gosto de fazer? Como que eu, particularmente, gosto de deixar os meus testes? Eu gosto de separar as áreas do teste em três grandes áreas. Given, when e then. Ok? No given, é tudo que a gente vai passar como parâmetro de entrada. E eu gosto de deixar bem explícito. Então, expected name, por exemplo. Eu gosto de deixar, vamos duplicar aqui, expected cpf, expected email. E aí a gente copia esses valores para cá. Vamos passar para cá também. esses valores pra cá vamos passar pra cá também, vamos deixar tudo bem explícito pra depois, ó, passar aqui exatamente o que a gente espera name beleza, e esse input ele também faz parte aqui do given, tá? então vamos vamos mover vamos mover vamos mover ele para cima. Beleza. O when é basicamente sempre ali a execução e obtenção do resultado. Então o que seria basicamente? A gente vai chamar um new create customer use case, por exemplo, então var use case, ah, e eu sempre gosto de usar final, tá, então é muito, vocês vão ver isso com frequência, vocês podem não colocar, vocês vão ver isso com frequência, vocês podem não colocar, mas é um hábito bom de se ter, é o equivalente a um const do JavaScript, ou seja, o apontamento dessa variável vai ser sempre mutável, você não vai conseguir mudar, mas eu tenho o costume de fazer, faça se você quiser, é um hábito bom de ter. Então, useCase, e aí useCase, ponto, a gente sabe que o useCase vai implementar o padrão command. Então ele vai ter um único método público chamado execute. E vai receber de entrada o createInput e vai retornar um output. E a gente vai pegar esse output e a gente vai comparar aqui com o que a gente recebeu de resposta. Então, o primeiro deles, assert non-null, que é o output.id. Então, eu imagino que esse output vai ter um identificador, a gente vai retornar ele. Depois, assert equals. Primeiro é o expected, então expected cpf. a gente vai retornar ele depois a frente e colos tá primeiro a expecta então expecta de cps e aí depois é o valor de fato é a resposta real é altos ponto cpf agora pra cá ao expect e mail expected email output.email e aí agora sim por último expected.name output.name fechou obviamente que tudo aqui está quebrando porque esse customer não existe inclusive a gente tem que renomear aqui o nome, Create Customer Use Case Test porque esse Customer não existe é, Test Create Customer, o toque é é difícil gente, é difícil mas vamos lá, então vamos criar o Customer, né então, a gente tem aqui, ó, no Application, a gente vai dar um Alt Insert num pacote novo, e a gente vai chamá-lo de useCases. Igual aqui embaixo, certo? Vou copiar isso aqui. Out insert, package, package não, perdão. Out insert, java class, create, customer, useCase. Esse customer, ele estende, ou seja, ele implementa uma abstração, que no caso, como é uma classe abstrata, ele estende de useCase, que é obrigado a definir um input e um output. record input input e o output beleza e a gente vai passar aqui o input Output E aí Out Enter Implement Method Execute E agora a nossa interface Já está compliance Com o O caso de uso A abstração, você pode até quebrar uma linha aqui Bonito e bem feito O que a gente espera de entrada? O que a gente falou que tinha de entrada ali no input? Expected CPF, email e name. Então vamos lá. String CPF, string email, string name. O que a gente fala que ele retorna? Isso tudo somado com um long ID, o identificador. Então, vamos começar a importar as coisas? O nosso querido Create Custom Music Case já parou de dar problema. Opa, o que eu fiz aqui? Beleza. Vamos importar o input do customer. Ó, já parou de quebrar. Já está funcionando, né? Se a gente rodar esse teste, ele vai funcionar? Não, porque a gente não implementou. A gente está retornando nulo. Então, como que a gente vai implementar aqui agora? Vamos lá. Vamos no controller. Cadê o nosso controller? Customer controller, vamos copiar isso aqui, vamos trazer para cá. Este acoplamento com o customer service, a gente, não vamos mexer agora, a gente vai mexer depois, então vamos trazer aqui ó, private, customer service, vou injetar aqui ó, esse service, vamos mudar, a gente vai, throw new, aqui a gente já pode fazer até uma primeira correção, ao invés de lançar um runtime exception, a gente pode criar aqui dentro um pacote, um pacote chamado exceptions, e a gente insere uma nova chamada validation exception beleza, extends de runtime exception e aí vamos adicionar uma sobrecarga aqui out insert construtor com todos esses parâmetros aqui, só que eu não quero esses parâmetros. E aí, enable suppression, false. Readable stack trace, false. Quer dizer, isso aqui a gente até pode deixar true, enable suppression. Mas o readable stack trace é importante deixar false, porque stack trace, cálculo de stack trace em aplicação de grande porte, gera um overhead sim considerável para a sua aplicação. Aplicações de auto throughput, para a JVM pausar, ela pede capturar stacktrace naquele momento e colocar na exception, isso tem um custo e em em aplicações de auto-droplet, esse custo é danoso. Então, eu sempre desabilito o stack trace e sempre crio exceptions que dizem o problema e eu consigo encontrar o problema com base no nome da exceção e o tipo do erro. E não na stack trace inteira. Compreendido? Eu só uso a stack trace nesses casos onde, por exemplo, eu recebi uma exception de alguma outra biblioteca a qual eu não tenho controle, então por isso eu estou deixando aqui um segundo parâmetro como trouble. Daí se vier de algum caso que eu não tenho control ali, a gente passa como segundo parametro mas eu evito no meu código lançar esse tipo de coisa com stack trace então validation exception e a gente pode colocar aqui customer already exists beleza, que que é isso aqui isso aqui é o input.cpf a gente até pode retornar um erro um pouco não nem vamos dar detalhes do erro sabe por que Por quê? Porque esse tipo de detalhe para hacker é algo rico. Ele saber que existe algum customer com aquele CPF ou com aquele e-mail, ele consegue validar aquele e-mail que aquele CPF de fato existe. Então, nem vamos validar, vamos só falar que o customer já existe. Beleza, e aqui ele está instanciando o customer,ando save, então a gente aqui novamente vamos mudar isso aqui input.name input.cpf input.email e aí a gente vai dar um save aqui e depois a gente vai retornar um new output customer.geted, customer.cpf, e-mail, name e aí é isso. Vamos lá então rodar o nosso teste para ver se ele está funcionando. Ah, claro, agora ele tem a dependência do customer service, né? Quem que é esse Customer Service? Vamos lá, vamos fazer o seguinte A gente vai instanciar o Customer Service aqui New Customer Service Ou melhor, vamos usar do Moquito A gente vai usar Moquito para mocar esse Customer Service Por que a gente está fazendo isso? Moquito para mocar esse Customer Service. Por que a gente está fazendo isso? Porque ele, dentro dele, tem um acoplamento com o repository, que por sua vez é uma interface. Mas como ele já começa a ficar muito complexo de ser construído, e não é o objetivo deste nosso teste, o escopo deste teste, entender do Customer Service para saber financiar ele, então a gente vai simplesmente usar do Moquito aqui. Então vamos passar ali o Customer Service e aí é o seguinte, o Customer Service ele basicamente precisa de uma resposta, né? Precisa dar para ver essa resposta porque ele está sendo mocado agora. Então, a gente vai utilizar aqui, por exemplo, when customerService.findByCPF e aí vai ser o expectedCPF then return optional empty. Vamos colocar um static import aqui duplicar essa linha find by email expected email optional empty e aí a gente vai duplicar save colocar aqui ó, n e aí a gente vai colocar then answer first and e aí a gente vai colocar then answer first and answer first arg cadê vamos deixa eu só importar aqui answers first returns first arg, então vamos ver se é isso mesmo agora sim, achei então, o que a gente está falando aqui? quando chamar o método save com qualquer parâmetro ele vai ser retornado este primeiro parâmetro. E aqui para os findById e findByEmail, a gente simplesmente vai retornar a int para deixar passar. Então, vamos rodar o nosso teste aqui para ver se ele está passando. E, opa, assert not null. Ah, claro, a gente não setou o querido id, né, então vamos lá o que a gente pode fazer então de diferente aqui a a gente vai pegar a.get argument zero que é do tipo customer . class que é do tipo customer.class customer e a gente vai dar um return no customer mas antes a gente vai setar um id qualquer aqui random.timestamp tá tranquilo agora sim mocado bonito not timebased id quebrando liscov quebrando liscov bacana random uid ponto significant most bytes ok, isso aqui também ou poderia ser um random etc ok, então o nosso teste já passou e reparem que agora a gente está testando especificamente o customer Ok, então o nosso teste já passou. E reparem que agora a gente está testando especificamente o Customer. A gente pode colocar os outros testes aqui também. Então vamos lá, vamos simular. Agora, quais quiseram os outros testes aqui? Vamos ver lá no Customer. os outros testes aqui vamos ver lá no customer não deve cadastrar um cliente com cpf duplicado vamos lá no nosso vamos e aqui a gente pode criar final var a customer igual a new customer a customer.setid vamos fazer a mesma coisinha aqui a customer.setcpf vamos colocar expected cpf afinal é a mesma coisa expected name expected email opa, setcpf set name set email expected email então, gerir um customer sete e-mail, expected e-mail. Então, gerei um customer, que é o que a gente vai retornar aqui. E aí, esse mock do find by email e o save nem é necessário ter, porque ele já vai falhar antes. A primeira verificação, se eu não me engano, é o CPF. E aí, é claro, ele dança não se recebe então a gente precisa aqui ó é a frente dos seus trouxos a certidão ea gente vai colocar aqui um vale exception e uma closure, uma lambda function. Aqui é actual exception. E aí a gente vai colocar assert equals expected error Customer already exists. E aí é exception.getMessage. Beleza. Show de bola. Vamos aqui executar então. E aí passou. E aí vamos só para finalizar aqui. Aproveitar a gente já faz os outros então é deixa eu fechar esses outros caras aqui só para chegar aqui mais rápido não deveria cadastrar um cliente com e mail duplicado que a gente vai mudar aqui agora o find by mail expected email e ele vai retornar esse cara e por último é o get por id que não compete a esse nosso repositório então é basicamente esse nosso caso de uso então é basicamente esses três testes que a gente estava cobrindo no controller que a gente passa a cobrir aqui né agora sim a gente tem certeza que o nosso caso de uso ele está completo para ser usado então o que a gente pode fazer aqui o customer controller a gente é a gente como a gente não vai trabalhar por enquanto com a edição de dependência né a gente que pode fazer a gente pode vir aqui ó e new customer use case, create customer use case passando customer service final var use case depois use case .execute new input gto.getcpf gto.getmail gto.getname final var output, igual, e aí a gente devolve output.id e um output aqui. Bacana? E aí, só para completar, a gente até pode colocar dentro de um trycat, né? A gente sabe que ele retorna uma validation exception, e quando retornar essa exception a gente pode retornar por exemplo um responsiente de unprocessable error com o body x.getMessage assim a gente garante que está tudo funcionando vamos executar os testes para ver? Vamos rodar todos os testes da nossa aplicação. Enquanto roda, falta um lugar que a gente deve trocar também. Vamos lá, todos os testes passaram, olha o GraphQL aqui, olha como ele estava, olha como ele pode ficar. Olha como ele estava, olha como ele pode ficar. E aí a gente só muda isso aqui para retornar, por exemplo, um new customer DTO, já que é a resposta dele. Então, id, customer, opa, output.cpf, output.name output. Vamos ver se ele tem qualquer aqui. Ah, ele nem tem esse... ele nem tem esse construtor. Então vamos fazer o seguinte. Vamos retornar output e a gente vai retornar o output aqui. Por enquanto. E ele está falando que eu posso retornar aqui direto. Ok. E a diferença é que aqui, por exemplo, não é de show, é input. E aí, se E a diferença é que aqui, por exemplo, não é edit.io, né? É input. E aí, se tiver algum tipo de erro aqui, a gente nem vai tratar. Aqui a gente vai deixar estourar mesmo. O render do GraphQL vai tratar por enquanto. A gente não se preocupa com isso. E, ó. Tá vendo? Diminuímos pra caramba as regras de negócio que estavam fora, que estavam dentro, acopladas lá no nosso controller, acoplada ao driver REST API. E passamos para o caso de uso através da porta, que na verdade é o contrato do caso de uso. E eu paro para perguntar para vocês. O REST API é o driver, o caso de uso, aqui que a gente está usando, está expondo a porta, que torna este nosso controller um adapter. Então o nosso controller aqui é um adapter. O CustomerResolver é a mesma coisa. Está vindo do GraphQL e está indo para a porta do CreateCustomer. Que torna o nosso Resolver um adapter. Novamente. Então esses caras são a parte da entrada ao hexágono agora a gente vai extrair os outros casos de uso e depois ver como é que fica as outras partes e também como é que a gente enriquece o nosso domínio e deixa de só trabalhar com as entidades anêmicas aqui que são só pojos, getters e setters, cujo não tem comportamento. Então é isso, vejo vocês na próxima aula.