<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eduardo Santana</title>
    <description>The latest articles on DEV Community by Eduardo Santana (@ezambomsantana).</description>
    <link>https://dev.to/ezambomsantana</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1250990%2F847b6ae6-ddb8-42bc-8198-2d0a66727396.jpeg</url>
      <title>DEV Community: Eduardo Santana</title>
      <link>https://dev.to/ezambomsantana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ezambomsantana"/>
    <language>en</language>
    <item>
      <title>Caixa de ferramentas da Arquitetura de Software [Parte-2]</title>
      <dc:creator>Eduardo Santana</dc:creator>
      <pubDate>Thu, 11 Apr 2024 14:33:39 +0000</pubDate>
      <link>https://dev.to/ezambomsantana/caixa-de-ferramentas-da-arquitetura-de-software-parte-2-3nog</link>
      <guid>https://dev.to/ezambomsantana/caixa-de-ferramentas-da-arquitetura-de-software-parte-2-3nog</guid>
      <description>&lt;p&gt;Continuando o texto que escrevi semana passada sobre o livro "Caixa de Ferramentas da Arquitetura de Software" hoje vou escrever sobre a terceira parte do livro que é focado na confiabilidade da aplicação.&lt;/p&gt;

&lt;p&gt;Se você não leu o primeiro post, você pode encontra-lo aqui:&lt;br&gt;
&lt;a href="https://dev.to/ezambomsantana/caixa-de-ferramentas-da-arquitetura-de-software-parte-1-2i7a"&gt;https://dev.to/ezambomsantana/caixa-de-ferramentas-da-arquitetura-de-software-parte-1-2i7a&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No post de hoje vou falar sobre a confiabilidade em uma aplicação, que é talvez um dos requisitos não funcionais mais importantes na Engenharia de Software, já que ele indica que a aplicação executa corretamente os requisitos funcionais para que ela foi projetado de forma confiável.&lt;/p&gt;

&lt;p&gt;Mas o que isso quer dizer? Primeiro que os requisitos estão implementados corretamente, se o usuário fizer uma operação ela vai executar exatamente o que ele esperava. &lt;/p&gt;

&lt;p&gt;Segundo, que a aplicação estará sempre disponível, você já deve ter visto um sistema indisponível, e sabe o quanto isso é frustrante. &lt;/p&gt;

&lt;p&gt;Por último, sabendo que por melhor que a aplicação seja, ela pode falhar, e se falhar, será possível recupera-la sem efeitos colaterais.&lt;/p&gt;

&lt;p&gt;Para garantir a confiabilidade da aplicação temos que pensar em todas as fases do software, iniciando do projeto e indo até a execução da aplicação. No processo de desenvolvimento temos que garantir que a aplicação cumpra os seus requisitos e que eles foram bem testados. &lt;/p&gt;

&lt;p&gt;No código, é necessário garantir que ele trate exceções e que a aplicação continue a funcionar mesmo em situações adversas, como um alto número de requisições por exemplo. Na infraestrutura precisamos garantir que a aplicação se recupere de possíveis falhas e também que a troca de versões não cause grandes momentos de indisponibilidade da aplicação.&lt;/p&gt;

&lt;p&gt;Vamos discutir um pouco mais a fundo como podemos aumentar a confiabilidade das aplicações em cada um dos estágios de uma aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confiabilidade no Desenvolvimento
&lt;/h3&gt;

&lt;p&gt;Para aumentar a confiabilidade da aplicação devemos começar a trabalhar ainda no processo de desenvolvimento, existem várias práticas nesse processo que ajudam a aumentar bastante a confiabilidade. &lt;/p&gt;

&lt;p&gt;Um exemplo é a revisão de código, essa prática ajuda muito em evitar problemas como mal entendimento das regras de negócio ou exceções que um desenvolvedor não pensou. O velho ditado que duas cabeças pensam melhor que um vale bastante na programação (como em praticamente qualquer outra coisa).&lt;/p&gt;

&lt;p&gt;Além da revisão outra prática que ajuda bastante é o desenvolvimento de testes automatizados. No mundo ideal, teríamos tempo para testar a aplicação inteira novamente a cada subida pra produção, mas sabemos que não é isso que acontece, pois isso levaria muito tempo. &lt;/p&gt;

&lt;p&gt;Assim, a única forma de ter segurança que uma mudança no código não teve efeitos inesperados é ter uma grande cobertura de testes automatizados.&lt;/p&gt;

&lt;p&gt;Existem várias ferramentas que podem ser usadas nessa fase do desenvolvimento de software. Algumas comuns são um bom sistema de controle de versão, como o Git, frameworks de teste como o JUnit e Mockito para Java e ferramentas que fazem análise de código e de cobertura de testes como o Sonar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confiabilidade no Código
&lt;/h3&gt;

&lt;p&gt;Pensando no código, existem várias implementações para aumentar a confiabilidade no código, uma indispensável é o tratamento de exceções, para garantir que erros inesperados não estourem na cara dos usuários. Por isso tratar exceções, e se possível se recuperar delas é essencial.&lt;/p&gt;

&lt;p&gt;Outra implementação importante em qualquer aplicação que tenha uma alta carga de trabalho é o rate limit (ou limitação de carga). Essa implementação evita um sobrecarga no servidor, e também pode ajudar a mitigar ataques do tipo DDoS, e caso um usuário passe do seu limite de requisições, o servidor pode retornar um erro 429 (Too Many Requests).&lt;/p&gt;

&lt;p&gt;Definir timeouts para chamadas a recursos externos também é uma prática importante. As vezes é melhor falhar logo do que ficar esperando por um tempo indeterminado ou muito grande. Lembrando que na maioria dos servidores, se uma thread está parada esperando uma resposta, ela não consegue atender outras requisições, desperdiçando recursos. &lt;/p&gt;

&lt;p&gt;Também relacionado a recursos externos, também vale a pena mencionar os Circuit Breakers que verifica se o recurso que a aplicação está acessando está enfrentando problemas (demora na respostas ou muitos erros) e caso sim pode interromper momentaneamente as chamadas para esse recurso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confiabilidade na Infraestrutura
&lt;/h3&gt;

&lt;p&gt;Pensando na infraestrutura, o passo mais obvio para garantir a confiabilidade é ter mais de uma instância rodando a aplicação. Isso pode ser feito usando um balanceador de carga (Load Balancer - LB) que vai distribuir as requisições entre duas ou mais instâncias de uma aplicação, ou em uma ferramenta de gerenciamento de conteineres, como o Kubernetes.&lt;/p&gt;

&lt;p&gt;Esse ideia de instâncias pode existir em vários níveis. Por exemplo, podem existir duas instâncias em um mesmo servidor, isso já é melhor do que nada, mas ainda pode ser insuficiente, pois se o servidor cair, as duas instâncias ficarão fora do ar. Em um provedor de cloud, é possível ter duas ou mais instâncias em diferentes áreas geográficas, o que diminui bastante a probabilidade de falhas totais.&lt;/p&gt;

&lt;p&gt;Obviamente que para isso a aplicação deve estar preparada. Um exemplo é que para permitir a execução de mais de uma instância, a aplicação não deve ter nada local, por exemplo, um token de autenticação não pode ser mantido diretamente na aplicação, senão um token só valerão naquela instância, para isso pode ser usado um cache distribuído como o Redis.&lt;/p&gt;

&lt;p&gt;Outro ponto bastante importante na infraestrutura é garantir a recuperabilidade da aplicação, isto é, a capacidade da aplicação se recuperar de problemas (já que problemas são inevitaveis). Um exemplo disso é se um servidor (ou VM) reiniciar automaticamente, a aplicação voltará a funcionar automaticamente ou precisará de uma intervenção humana? &lt;/p&gt;

&lt;p&gt;Outro exemplo de recuperabilidade são os backups, eles são essenciais para o caso de perda de dados seja possível recuperar a aplicação para um ponto não tão distante do atual. Uma dica sobre backups, nunca os guarde na mesma máquina onde a aplicação está sendo executada.&lt;/p&gt;

&lt;p&gt;Por fim, um último requisito indispensável para a confiabilidade da aplicação é o seu monitoramento. Isso importante tanto para a aplicação quanto para a infraestrutura. Existem várias ferramentas que podem ser usadas para isso como o Prometheus, Grafana e o Dotadog.&lt;/p&gt;

&lt;p&gt;Se tiver interesse no livro, você pode encontrar diretamente no site da Casa do Código:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.casadocodigo.com.br/products/livro-caixa-de-ferramentas-da-arquitetura-de-software"&gt;https://www.casadocodigo.com.br/products/livro-caixa-de-ferramentas-da-arquitetura-de-software&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ou na Amazon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.amazon.com.br/Caixa-ferramentas-Arquitetura-Software-aplica%C3%A7%C3%B5es-ebook/dp/B0CYJV5P11/ref=rvi_d_sccl_1/147-7357894-3056112"&gt;https://www.amazon.com.br/Caixa-ferramentas-Arquitetura-Software-aplica%C3%A7%C3%B5es-ebook/dp/B0CYJV5P11/ref=rvi_d_sccl_1/147-7357894-3056112&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Caixa de ferramentas da Arquitetura de Software [Parte-1]</title>
      <dc:creator>Eduardo Santana</dc:creator>
      <pubDate>Mon, 25 Mar 2024 15:54:55 +0000</pubDate>
      <link>https://dev.to/ezambomsantana/caixa-de-ferramentas-da-arquitetura-de-software-parte-1-2i7a</link>
      <guid>https://dev.to/ezambomsantana/caixa-de-ferramentas-da-arquitetura-de-software-parte-1-2i7a</guid>
      <description>&lt;p&gt;Vou escrever uma série de publicações para descrever um pouco mais profundamente o conteúdo do meu livro "Caixa de ferramentas da Arquitetura de Software: Como tornar suas aplicações mais escaláveis, confiáveis e seguras" publicado pela Casa do Código no dia 19/03/2024.&lt;/p&gt;

&lt;p&gt;Neste texto vou dar uma visão geral das duas primeiras partes do livro. O livro é dividido em 5 partes, a primeira parte é uma introdução a arquitetura de software, nela descrevo algumas visões sobre o que é arquitetura de software e mostro algumas das organizações mais comuns que são usadas para o desenvolvimento de software.&lt;/p&gt;

&lt;p&gt;Depois, na segunda, terceira e quarta parte entro em cada um dos requisitos destacados no subtítulo do livro, que são &lt;strong&gt;Escalabilidade&lt;/strong&gt;, &lt;strong&gt;Confiabilidade&lt;/strong&gt; e &lt;strong&gt;Segurança&lt;/strong&gt;. Esse requisitos são fortemente influenciados pela arquitetura de uma aplicação, e existem diversas ferramentas que podem ser utilizadas para atingir os objetivos da aplicação.&lt;/p&gt;

&lt;p&gt;Na segunda parte eu foco em três requisitos importantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desempenho: Relacionado principalmente ao tempo de resposta da aplicação. Normalmente, esse tempo deve ser o menor possível, mas no mínimo ele deve atender as expectativas do usuário. Por exemplo, uma rota REST síncrona deve responder em alguns poucos segundos, se o tempo for muito maior que isso, será necessário pensar em alternativas para implementar essa rota, como por exemplo implementar uma rota assíncrona, que irá avisar o usuário quando o processamento está completo.&lt;/li&gt;
&lt;li&gt;Escalabilidade: Uma aplicação pode funcionar bem com poucos usuário, mas e se a carga aumentar, ela continua funcionando bem? Se sim, a aplicação é escalável, isso tem bastante relação com desempenho, normalmente algoritmos e aplicações eficientes são escaláveis, mas existem técnicas que podem aumentar a escalabilidade até de aplicações que podem ter desempenhos não tão bons, como cache e balanceamento de carga.&lt;/li&gt;
&lt;li&gt;Elasticidade: Muitas vezes é necessário usar uma grande infraestrutura para garantir a escalabilidade de uma aplicação. Porém, se a carga da aplicação varia muito, manter toda essa infraestrutura ligada o tempo todo pode desperdiçar muitos recursos. Imagine uma aplicação de entrega de comida, ela tem picos muito bem definidos nos horários do almoço e jantar, nessa hora a infraestrutura tem que estar toda funcionando, mas durante a madrugada, é possível atender toda a demanda com muito menos recursos. Isso pode diminuir drasticamente o custo para a execução da sua aplicação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esses três requisitos são extremamente importantes para manter a satisfação dos usuários da aplicação, mas sem que os custos explodam. Por exemplo, pode ser fácil garantir  desempenho e a escalabilidade de uma aplicação, basta executa-la em uma máquina com uma quantidade grade de recursos (memória, cpu, disco, rede, ...) ou em um cluster com uma grande quantidade de VMs. &lt;/p&gt;

&lt;p&gt;Porém, o custo disso pode ser muito alto. Por isso é extremamente importante conhecer técnicas que podem aumentar a capacidade de uma aplicação antes de simplesmente aumentar a quantidade de recursos utilizados para executar a aplicação.&lt;/p&gt;

&lt;p&gt;No próximo post vou falar mais sobre a terceira parte do livro que foca na confiabilidade das aplicações. Até lá!&lt;/p&gt;

</description>
      <category>livro</category>
      <category>arquiteturadesoftware</category>
      <category>escalabilidade</category>
      <category>desempenho</category>
    </item>
    <item>
      <title>Testing a Spring application with MongoDB aggregations</title>
      <dc:creator>Eduardo Santana</dc:creator>
      <pubDate>Sun, 07 Jan 2024 20:20:47 +0000</pubDate>
      <link>https://dev.to/ezambomsantana/testing-a-spring-application-with-mongodb-aggregations-3jpb</link>
      <guid>https://dev.to/ezambomsantana/testing-a-spring-application-with-mongodb-aggregations-3jpb</guid>
      <description>&lt;p&gt;Currently, I am working on an application that involves various MongoDB aggregations to calculate sums, averages, among many other things. &lt;/p&gt;

&lt;p&gt;I am using MongoDB's standard classes to implement these aggregations, rather than Spring Data, mainly to leverage MongoDB Compass's functionality to generate aggregation code that can be directly executed within the tool. The figure below illustrates how this can be done:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I7lDac-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c6sl0m6f0e3il3kcbbzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I7lDac-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c6sl0m6f0e3il3kcbbzs.png" alt="Exporting MongoDB Aggregation to Language" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The challenge now is how to test these aggregations. It would be possible to mock all the MongoDB classes and test the Java code. However, these tests may not be very useful since the complexity lies mainly in the aggregations, not in the code itself.&lt;/p&gt;

&lt;p&gt;To address this, I remembered that some time ago, I used an embedded Postgres in a Spring application and decided to verify if it was possible to do the same with MongoDB. I found the &lt;strong&gt;de.flapdoodle.embed.mongo.spring30x&lt;/strong&gt; library, which made this task possible. In this article, I will show a simple example of how to implement testing for a MongoDB aggregation using an embedded database instance.&lt;/p&gt;

&lt;p&gt;The complete application code is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ezambomsantana/mongodb-testing"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I developed a very simple application that has three routes: one for creating users, another for listing users, and a third one that performs an aggregation on users, grouping them by city and calculating the average salary and age of the users.&lt;/p&gt;

&lt;p&gt;The challenge is testing the method that performs the aggregation; it utilizes MongoDB access classes such as AggregateIterable and MongoDatabase. The code snippet below illustrates the implementation of this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt; &lt;span class="n"&gt;mongoClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// other methods to save and list users&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAvg&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mongoClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCollection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$group"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"_id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$city"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avgAge"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$avg"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$age"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avgSalary"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$avg"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$salary"&lt;/span&gt;&lt;span class="o"&gt;)))));&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cityAggregationDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;cityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"_id"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;cityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAvgSalary&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avgSalary"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;cityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAvgAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avgAge"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code performs the aggregation by grouping users based on the city they live in and then calculating the average salary and age per city. This aggregation returns a list of results, with each object representing a different city.&lt;/p&gt;

&lt;p&gt;Let's test this code now. To do that, the first step is to add the 'de.flapdoodle.embed.mongo.spring30x' library to the pom.xml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;de.flapdoodle.embed&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;de.flapdoodle.embed.mongo.spring30x&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.6.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to add an entry to the application.properties file for testing (remember to create this file in src/test/resources/application.properties). This property indicates which version of MongoDB will be used for testing. In this case, I am using version 6.0.1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;de.flapdoodle.mongodb.embedded.version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;6.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can create our test. To do that, let's create the UserServiceTests class. The following code shows the declaration of this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@AutoConfigureDataMongo
@SpringBootTest
public class UserServiceTests {


    @Autowired
    private UserService userService;

    @Autowired
    private MongoClient mongoClient;

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the tests, we need to add some data to the embedded database. We can use the @BeforeEach annotation with a method that will be executed before the tests. This method adds some users to MongoDB. Note that I am also clearing the user collection before inserting the data. This is optional and depends on what you want to achieve with your tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@BeforeEach&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;MongoDatabase&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mongoClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;MongoCollection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCollection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Eduardo"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SP"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"salary"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can create and run the tests. This part is straightforward since we are not mocking any classes, and the data has already been inserted into the database in the previous method. So, basically, we just need to call the method we want to test and then verify if the aggregation data came as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test_aggregateUsersSuccessfully&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CityAggregationDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAvg&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SP"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getCity&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getAvgAge&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getAvgSalary&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>mongodb</category>
      <category>testing</category>
      <category>java</category>
      <category>spring</category>
    </item>
  </channel>
</rss>
