<?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: joaosczip</title>
    <description>The latest articles on DEV Community by joaosczip (@joaosczip).</description>
    <link>https://dev.to/joaosczip</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%2F447302%2Ffc788fb2-ad42-4367-9931-605efc10e19a.png</url>
      <title>DEV Community: joaosczip</title>
      <link>https://dev.to/joaosczip</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joaosczip"/>
    <language>en</language>
    <item>
      <title>Scale-up and Scale-out</title>
      <dc:creator>joaosczip</dc:creator>
      <pubDate>Mon, 29 Apr 2024 13:22:01 +0000</pubDate>
      <link>https://dev.to/joaosczip/scale-up-and-scale-out-30fa</link>
      <guid>https://dev.to/joaosczip/scale-up-and-scale-out-30fa</guid>
      <description>&lt;p&gt;Does your application fit your users' needs?&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;A common problem that companies are facing today, especially the big ones, is the growing number of concurrent users using their applications. If their systems are not prepared to handle all the requests they are receiving, it can be very problematic for the company as a whole.&lt;/p&gt;

&lt;p&gt;Imagine a company whose business is an e-commerce platform, &lt;strong&gt;black-friday&lt;/strong&gt; is coming and the engineering team hasn’t taken any actions to ensure the platform's availability and resilience on that day. When the day arrives, the number of simultaneous access has grown in a way that even the most optimistic executive wouldn’t imagine. What a great news! Not so great though… the platform becomes unavailable, and &lt;strong&gt;users are unable to even access it&lt;/strong&gt;. Buying things? Not a change!&lt;/p&gt;

&lt;p&gt;How harmful for the company this situation can be? There are a lot of e-commerce platforms waiting for black-friday every year. Sometimes they already forecasted the GMV for this day, and are only expecting Monday morning to collect the results of the whole weekend to celebrate.&lt;/p&gt;

&lt;p&gt;Now, on the other hand, how this situation could have been if the business had an agreement with the engineering team? How the engineering team could help in this situation? How the whole platform could be prepared to face this highly growing peak?&lt;/p&gt;

&lt;h2&gt;
  
  
  About scaling
&lt;/h2&gt;

&lt;p&gt;During peak loads, as the number of simultaneous access is growing on your system, the application needs to keep working as it was before, in a way that the users don’t end up being harmed by it.&lt;/p&gt;

&lt;p&gt;Scaling is a process in which your software adapts to your users’ needs, growing and shrinking whenever it’s necessary. This process is responsible for responding to the different types of loads, ensuring its availability and resilience to keep working as expected by your users. It must be as transparent as possible, ensuring that not a single user will be impacted by it.&lt;/p&gt;

&lt;p&gt;There are a lot of problems that can arise when the number of users accessing your application is high, and I’ll explain them below.&lt;/p&gt;

&lt;p&gt;In simple terms, your system can operate in two different loads: normal and high, and it must be prepared to face both of them. Figure 1 demonstrates the differences between these loads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbclpyptpe53j80de9xr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbclpyptpe53j80de9xr.png" alt="Figure 1 — Different loads on your system&amp;lt;br&amp;gt;
" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In simple terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Normal load&lt;/strong&gt;: the number of concurrent users using your system is under normal usage, it’s receiving a known number of requests and as a consequence, using nothing but an expected number of resources from your servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High load&lt;/strong&gt;: the number of concurrent users is above normal, it’s receiving a lot of simultaneous requests, and as a consequence, using a lot of resources from the servers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given that context, in which case your application can be more harmful to the company if it isn’t capable of handling the situation as expected? In general, if you guess the last one, you’re right! However, the first one can be quite harmful if you aren’t prepared.&lt;/p&gt;

&lt;p&gt;We have already explained above why not being prepared to face the high load situation may be very stressful. But why the system must be prepared to face the normal load as well? Imagine a scenario where your system has a few concurrent users, receiving nothing but a few requests, but your servers are prepared to handle a lot of requests, and you have provisioned a great amount of CPU and RAM to it. This CPU and RAM will cost you, especially if you are running your infrastructure on the cloud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provisioning many resources (CPU and RAM) when your application is under low-normal usage will end up being too expensive for the company.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With that being said, how to be prepared for both scenarios? Not underusing your resources and being capable of staying available?&lt;/p&gt;

&lt;p&gt;There are two types of scaling to help you with that, and you will decide which to use depending on your application needs. They are &lt;strong&gt;vertical scaling&lt;/strong&gt; and &lt;strong&gt;horizontal scaling&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical scaling
&lt;/h2&gt;

&lt;p&gt;Imagine a scenario where your application is running on a single server machine, with 4 GB of RAM and 2 CPU Cores, and it is under normal usage. But suddenly the number of users starts increasing, you are under a high load now and your application starts becoming slow and unavailable.&lt;/p&gt;

&lt;p&gt;In that case, you have decided to upgrade your server resources. You add 4 more GB of RAM, and 2 more CPU Cores, now your machine has a total of 8 GB of RAM and 4 CPU Cores. With this upgrade your application becomes more stable, it isn’t presenting slowness and it’s more available now. The users are pretty happy.&lt;/p&gt;

&lt;p&gt;This process of upgrading your machine (or choosing a more robust one) is called &lt;strong&gt;Vertical Scaling&lt;/strong&gt;, or &lt;strong&gt;Scale-up&lt;/strong&gt;. &lt;strong&gt;Figure 2&lt;/strong&gt; illustrates this process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F370vhy2ji449tbagssj9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F370vhy2ji449tbagssj9.png" alt="Figure 2 — Vertical scaling or scale-up" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This approach can help in some cases, but it is definitely not suited for all situations.&lt;/p&gt;

&lt;p&gt;The most common usage of Vertical Scaling is the situation where your load is more &lt;strong&gt;predictable&lt;/strong&gt;. Where almost all of the time your load operates on a plateau and it does not change (increase or decrease) for a long period. And this is true because the process of scaling up your server isn’t quick. Your users will face a period of downtime while you are upgrading your resources.&lt;/p&gt;

&lt;p&gt;In an on-premise situation, there isn’t a way to upgrade the server resources without shutting it down before. Or even in a cloud environment, if you change your VM, the users won’t be able to access it until the new machine is up and running with your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;: As explained above, when scaling up your server on an on-premise environment, the process is upgrading the machine resources, using more CPU and RAM should do the trick. When handling this situation in a cloud environment, you can just choose a more robust VM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Management&lt;/strong&gt;: Running it on the cloud or on-premise, you’ll just need to manage a single machine. It’s easier than managing multiple machines (this will be explained below in more detail).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Costs&lt;/strong&gt;: Having a single machine running is cheaper than having 5 or 10 for example.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single point of failure&lt;/strong&gt;: As you have just a single server running your application, what will happen if your server goes down? Besides planning the scaling, you must be prepared to face downtimes either.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hardware limitations&lt;/strong&gt;: There’s a hardware limit that each machine can run, you cannot add resources infinitely to your server. This limit can be a bottleneck if the application usage keeps growing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Downtimes&lt;/strong&gt;: When upgrading your server, the application will be off until the scaling process is finished. During this time, your users won’t be able to use your software. You must ensure that scaling your application won’t affect your current users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Costs&lt;/strong&gt;: In some cases, you’ll just need 10% more resources than your server currently has, however, depending on which cloud provider you are running your app, adding this 10% additional hardware can end up costing 50% more at the end of the month.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Horizontal Scaling
&lt;/h2&gt;

&lt;p&gt;In contrast to the Vertical Scaling approach where more resources are added to a single machine, in the &lt;strong&gt;Horizontal Scaling&lt;/strong&gt; (or &lt;strong&gt;Scale-out&lt;/strong&gt;) approach, more machines are added to handle the application’s traffic.&lt;/p&gt;

&lt;p&gt;Getting back to our &lt;strong&gt;black-friday example&lt;/strong&gt;, the moment that the concurrent users start growing, copies of the same server are added and the traffic that was previously redirected to a single instance now is routed to each one of the new server instances. These copies contain the same specs as the original one, and now your application is prepared to handle an increased load.&lt;/p&gt;

&lt;p&gt;When using this approach, normally the servers will have low hardware resources, instead of 8 GB of RAM, it’ll probably be less than 512 MB, for example. This happens because rather than running your application on a VM, you’ll use containers alongside a container management system like Kubernetes or AWS ECS. Containers are way smaller than VM instances, and they are built to scale horizontally, e.g. running a lot of instances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 3&lt;/strong&gt; illustrates the process of scaling out your system where the number of concurrent users is growing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvndugaa76kg5ehdbqo9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvndugaa76kg5ehdbqo9v.png" alt="Figure 3 — Horizontal scaling or scale-out" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This process is all abstracted by the management system you choose. For Kubernetes for example, the &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/"&gt;HPA&lt;/a&gt; will take care of scaling your instances.&lt;/p&gt;

&lt;p&gt;But adding more instances isn’t enough to fully scale your system horizontally, it also needs to know how to properly balance its load between all these instances.&lt;/p&gt;

&lt;p&gt;When you have a single instance running it’s easier because all the traffic is routed to it, however, how to route the traffic when you have multiple instances running at the same time? R: &lt;strong&gt;Load Balancer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Load balancing&lt;/strong&gt; is the process of routing the requests to different application instances, this is done by a &lt;strong&gt;Load Balancer&lt;/strong&gt; that sits in front of your instances and receives all the requests sent to your application. When receiving these requests, the Load Balancer knows to which instance redirects the requests.&lt;/p&gt;

&lt;p&gt;There are a lot of different load balancing algorithms that your Load Balance can use, these algorithms not just route the requests, but they also take care to not overload a single container with too many requests, they try to balance the load as evenly as possible.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Figure 4&lt;/strong&gt; below there’s an illustration of a Load Balancer sitting in front of the containers to receive and redirect its load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqg8kd6ln7b01d8yw14kj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqg8kd6ln7b01d8yw14kj.png" alt="Figure 4 — Scaling out with a Load Balancer&amp;lt;br&amp;gt;
" width="800" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Horizontal Scaling approach is more suitable for cases where your load &lt;strong&gt;isn’t predictable&lt;/strong&gt;, that is, it can increase and decrease many times during a single day.&lt;/p&gt;

&lt;p&gt;This type of scaling allows more flexibility because it knows how to scale and shrink when necessary. You can configure different scaling thresholds, like RAM and CPU usage, HTTP metrics, or even asynchronous events like AWS SQS messages.&lt;/p&gt;

&lt;p&gt;For example, you have set up your scaling based on HTTP metrics, once your app starts receiving a lot of concurrent HTTP requests, your management systems know that it needs to provision other instances to handle all the traffic. When the load decreases, the provisioned instances are killed to avoid unnecessary additional costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redundancy&lt;/strong&gt;: As you have multiple instances of your server running, if one of them fails, or gets killed for whatever reason, you’ll always have another instance to handle the traffic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No downtime&lt;/strong&gt;: Even if you have just a single instance running, if it fails, your management system will know it and will provision another instance for you. This new instance will start receiving the requests from the one that just died.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fewer hardware limitations&lt;/strong&gt;: The hardware limitations are smaller, but it does not mean that it doesn’t exist. When scaling out your containers, you can scale it as much as you need once the required resources are available within your cluster. The limitations are in the cluster, as bigger your cluster is, the fewer limitations you’ll face.&lt;br&gt;
Performance: You can increase your system's parallel processing power by adding more instances to it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Management complexity&lt;/strong&gt;: Rather than managing a single instance, now you have N instances to manage. Usually, your container management system will do it for you, but it does not mean you won’t need to know how to use it. Depending on your scenario, company size, and some other factors, you’ll probably need someone specialized in those systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Costs forecasting&lt;/strong&gt;: It’s harder to forecast the costs without knowing how much hardware you’ll use within a month. Is not impossible, but it’s trickier than when managing a single server.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As the software applications are evolving, the users are becoming more demanding about the products they are using. If your application does not fit your user’s needs, it’s more likely for them to choose a different vendor.&lt;/p&gt;

&lt;p&gt;When projecting your software, the non-functional requirements are as important as the functional ones. Users start using your app for what it provides for them but stop using it for what it doesn’t.&lt;/p&gt;

&lt;p&gt;Choose a &lt;strong&gt;Vertical Scaling&lt;/strong&gt; approach when your app usage is more likely to remain the same almost all the time and a &lt;strong&gt;Horizontal Scaling&lt;/strong&gt; when it is not predictable and is most likely to vary often.&lt;/p&gt;

&lt;p&gt;Now that you know how to approach scaling, does your application fit your users’ needs?&lt;/p&gt;

&lt;p&gt;Resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cloudways.com/blog/horizontal-vs-vertical-scaling/"&gt;https://www.cloudways.com/blog/horizontal-vs-vertical-scaling/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudzero.com/blog/horizontal-vs-vertical-scaling/"&gt;https://www.cloudzero.com/blog/horizontal-vs-vertical-scaling/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/basics/horizontal-vs-vertical-scaling"&gt;https://www.mongodb.com/basics/horizontal-vs-vertical-scaling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>scaling</category>
      <category>architecture</category>
      <category>distributedsystems</category>
      <category>microservices</category>
    </item>
    <item>
      <title>What I learned in the Real Python testing courses</title>
      <dc:creator>joaosczip</dc:creator>
      <pubDate>Thu, 01 Feb 2024 10:41:06 +0000</pubDate>
      <link>https://dev.to/joaosczip/what-i-learned-in-the-real-python-testing-courses-14ni</link>
      <guid>https://dev.to/joaosczip/what-i-learned-in-the-real-python-testing-courses-14ni</guid>
      <description>&lt;p&gt;I recently completed the three main courses on automated testing from the Real Python platform. As I already use these tools in my daily work, I took the courses with the goal of understanding, in general, if there are better ways to write tests than how I do daily.&lt;/p&gt;

&lt;p&gt;Below, you will find my overview of the three courses I completed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://realpython.com/courses/testing-your-code-with-pytest/"&gt;Testing your code with pytest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/courses/python-mock-object-library/"&gt;Improve Your Tests With the Python Mock Object Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/courses/test-driven-development-pytest/"&gt;Test-Driven Development With pytest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing your code with pytest
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.pytest.org/en/7.4.x/"&gt;pytest&lt;/a&gt; is a framework for writing automated tests in Python that emerged as a counter to the unittest framework, which is part of the language's standard library.&lt;/p&gt;

&lt;p&gt;Unlike the latter, which has a very verbose approach where every test case must extend from a test class, pytest brings much greater simplicity, aligning much more closely with the concept of simplicity imposed by the language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing tests
&lt;/h3&gt;

&lt;p&gt;Below is an example of writing a test using unittest vs pytest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;# unittest
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestMyFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# pytest
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the example above, it's possible to observe the simplicity of pytest in comparison to its alternative. We can write a test just by declaring a function with the test_ prefix and use the reserved word assert to validate that the comparison is true, making the test pass.&lt;/p&gt;

&lt;p&gt;Conversely, it's also possible to do negative conditions just by changing the sign of the comparison:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;# pytest
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello! World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can perform comparisons between different objects, such as lists, tuples, dictionaries, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_equal&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_tuple_equal&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;assert &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_dict_equal&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, writing tests in pytest works as follows:&lt;/p&gt;

&lt;p&gt;Write a function with the test_ prefix;&lt;br&gt;
Use the word assert to ensure that the comparison is returning True.&lt;/p&gt;

&lt;p&gt;It's that simple!&lt;/p&gt;
&lt;h3&gt;
  
  
  Using fixtures
&lt;/h3&gt;

&lt;p&gt;In many cases, we want to write tests based on the same input argument. For example, given a list, we want to test different situations involving it.&lt;/p&gt;

&lt;p&gt;One way would be to define this list in all the tests and use it, as in the examples below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_pop&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_append&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_reverse&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although it works, writing tests in this manner brings some problems, especially related to difficulties in maintenance and evolution, since for each new test it will be necessary to define the same object. Besides, if there is any change in the object we are testing, it will need to be changed in all tests, leading to poor maintainability.&lt;/p&gt;

&lt;p&gt;pytest provides the possibility to define fixtures that will be reused among tests, in order to solve the problems highlighted above. Using fixtures, we can define any type of object we want to reuse during the tests, making any changes to this object be made in just one place.&lt;/p&gt;

&lt;p&gt;To do this, simply use the @pytest.fixture decorator and define the object we will work with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_list_reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To declare a new fixture, simply add the decorator right above the declaration of a function that returns the desired object. Once declared, we need to provide the name of the fixture in the tests where we want to use it, and pytest takes care of loading it within the tests.&lt;/p&gt;

&lt;p&gt;In addition to being able to define custom fixtures, pytest also provides a list of built-in fixtures that can be consulted here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameterizing tests
&lt;/h3&gt;

&lt;p&gt;Depending on the function you want to test, it's beneficial to test it with various different parameters in order to stress it as much as possible and ensure that it won't have side effects.&lt;/p&gt;

&lt;p&gt;If, for example, we wanted to test a function that performs subtraction between two numbers, we could follow the approach below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_subtract_2_and_1&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_subtract_5_and_2&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_subtract_10_and_5&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although this approach works, we end up returning to the problem of maintainability, because working in this way makes our tests more difficult to maintain, since any change in the signature or return of the function would result in changes in more than one test, and consequently in a greater effort of refactoring.&lt;/p&gt;

&lt;p&gt;To solve this problem, pytest provides us with another decorator responsible for supplying various parameters to the same test. Using this decorator, we can specify what the input parameters are and what output the function will have for the provided parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.mark.parametrize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;param_a,param_b,expected_result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected_result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected_result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The @pytest.mark.parametrize decorator takes two arguments:&lt;/p&gt;

&lt;p&gt;A string representing the parameters that will be passed to the test function.&lt;br&gt;
A list that represents each of the parameters that will be provided in each iteration of the test. When there is more than one parameter, as in the example above, we use a tuple to distinguish them within the list.&lt;/p&gt;
&lt;h3&gt;
  
  
  Course conclusion
&lt;/h3&gt;

&lt;p&gt;The course is a good introductory content, as it covers all the fundamental topics of the tool. By the end of this course, the developer should be able to write their first tests using the framework.&lt;/p&gt;

&lt;p&gt;Due to pytest being quite simple to use, and also because its documentation is very comprehensive, a course cannot stand out in such a way that it seems indispensable for learning. However, I missed some topics such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installation and setup of pytest, including the configuration file and its parameters;&lt;/li&gt;
&lt;li&gt;Test coverage collection;&lt;/li&gt;
&lt;li&gt;Debugging;&lt;/li&gt;
&lt;li&gt;Best practices for test writing;&lt;/li&gt;
&lt;li&gt;Other commands and functionalities of the tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generally speaking, I would say that you can learn everything the course shows just through the framework's documentation. Since it is a very simple tool to learn, the course could very well have covered the topics I mentioned above to ensure that the student not only knows how to use the tool itself but also how to write well-written and useful tests.&lt;/p&gt;
&lt;h2&gt;
  
  
  Improve Your Tests With the Python Mock Object Library
&lt;/h2&gt;

&lt;p&gt;When working with automated tests, often it's necessary to "simulate" the behavior of some object or dependency so that the test can be implemented. This simulation occurs mainly in cases where your Subject Under Test (SUT) has external dependencies, such as HTTP calls, database interactions, etc.&lt;/p&gt;

&lt;p&gt;In testing, we call this simulation a Mock. We mock a certain object when we can specify what its behavior will be during that specific test, determining the results of calls, the parameters used to call it, etc.&lt;/p&gt;

&lt;p&gt;To clarify the necessity of this procedure, I provide an example of a method that needs to perform a GET request to another API. In this case, our test should not perform the call itself, as doing so would make it heavily dependent on the quality of the connection and the API being called. This can bring problems since if the API is not functioning correctly or is not available at the time of executing the test, it will fail. There's also the issue related to the requests themselves, as a large test load can impact the performance of the API operating in a production environment, bringing unexpected effects.&lt;/p&gt;

&lt;p&gt;For these and other reasons, we use a Mock to simulate the behavior of the function making this GET call so that it does not make the call itself but only returns a predetermined result that makes sense for our test.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Mock object
&lt;/h3&gt;

&lt;p&gt;The Mock object is imported and used through the language's standard library (from version 3.3 onwards, for earlier versions it needs to be installed as a dependency), and it has a &lt;a href="https://docs.python.org/3/library/unittest.mock.html"&gt;documentation&lt;/a&gt; that is very clear and comprehensive on how to use it.&lt;/p&gt;

&lt;p&gt;The Mock class is quite flexible; once instantiated, we can make calls to methods that don't exist, and these methods will be attributed to the instance. Through this assignment, it is possible to carry out all the mocking operations we wish.&lt;/p&gt;

&lt;p&gt;One of the functions of Mock is to take on the role of a real instance (production class or method) and make them return specific results, as in the example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s not the original return&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s not the original return&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to specifying the return of methods, it's also possible to perform asserts on the calls to the method in question.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mock has a &lt;a href="https://docs.python.org/3/library/unittest.mock.html#the-mock-class"&gt;list&lt;/a&gt; of methods that can be used to ensure that the calls were made in the way we want.&lt;/p&gt;

&lt;p&gt;Every object to which a Mock instance is attributed inherits all its methods. Therefore, as demonstrated in the examples above, my_instance becomes an instance of Mock and no longer of MyProductionClass. When listing the methods of the my_instance instance, the result is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
[
    &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_any_call&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_called&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_called_once&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, 
    &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_called_once_with&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_called_with&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_has_calls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, 
    &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assert_not_called&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attach_mock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;call_args&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;call_args_list&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, 
    &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;call_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;called&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;configure_mock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;method_calls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mock_add_spec&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, 
    &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mock_calls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reset_mock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;return_value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;side_effect&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;some_method&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
]
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned list are the methods that can be used from my_instance to test the behavior of the instance in question.&lt;/p&gt;

&lt;p&gt;In addition to returning values, in some cases, we'll want to cover failure scenarios, or rather, scenarios of side effects. It's possible to throw exceptions to simulate these behaviors through the Mock object as well.&lt;/p&gt;

&lt;p&gt;Returning to our example of a GET request, when we have an HTTP call, various errors can happen, such as timeout, service unavailable, etc. We can simulate a timeout in our GET call through the Mock object.&lt;/p&gt;

&lt;p&gt;For example, we want to make a request to fetch all the holidays for the year 2024, and for this, we will use an API that returns all the holidays for a given year. We can force a timeout error once we mock the requests object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://holidays.com/api/holidays?year=2024&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays_timeout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;side_effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;too much time to complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way, we simulate an undesirable behavior of the method and can work on that, without actually making the HTTP call.&lt;/p&gt;

&lt;p&gt;Continuing with our example of the HTTP call, we can use the mock to return more complex objects, such as the response from this call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://holidays.com/api/holidays?year=2024&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mocked_response&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we instantiate a simulated response, mocked_response, and use the flexibility of the Mock class to specify the desired return.&lt;/p&gt;

&lt;p&gt;The side_effect method is not only used to throw exceptions but also for cases where we make the call to the same method more than once and receive different results, or even the same result.&lt;/p&gt;

&lt;p&gt;In the example below, the first request returned a timeout, due to the error we try again, and in the second request, we get the expected result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;requests.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://holidays.com/api/holidays?year=2024&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays_retry&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;side_effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first call, a timeout occurs and the exception is thrown. The second call is successful, and we get the expected return.&lt;/p&gt;

&lt;p&gt;This behavior can also be assigned at the moment of instantiating Mock, by providing the desired returns directly in its constructor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays_retry&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]))&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;side_effect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Patching
&lt;/h3&gt;

&lt;p&gt;Assigning a Mock instance to the object whose behavior we wish to simulate works well in cases where the test module has access to the same dependencies as the production module. However, in many cases, both modules will be separated, and the test will hardly have access to the same instances that the production class has.&lt;/p&gt;

&lt;p&gt;Therefore, we can use a technique called patching so that the Mock of the dependency is injected directly into our test.&lt;/p&gt;

&lt;p&gt;In the above examples of the GET call, both the &lt;code&gt;get_holidays&lt;/code&gt; function and its test &lt;code&gt;test_get_holidays&lt;/code&gt; are in the same file, so the test has access to the same instance of requests that the function has. If this were not true, it would be necessary to use patching.&lt;/p&gt;

&lt;p&gt;Patching can be used as a decorator or a context manager. Below are examples using both approaches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# holidays.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://holidays.com/api/holidays?year=2024&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="c1"&gt;# test_holidays.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;

&lt;span class="nd"&gt;@mock.patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;holidays.requests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# using as a decorator
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mocked_requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mocked_requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mocked_response&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When used as a decorator, the object will be injected into the list of arguments of the test function. This object will be a Mock instance, and all mocking operations can be performed normally from it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test_holidays.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# using as a context a manager  
&lt;/span&gt;        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;holidays.requests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mocked_requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;mocked_requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mocked_response&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it as a context manager is quite similar, with the major difference being that the instance is created within the test, instead of being injected.&lt;/p&gt;

&lt;p&gt;In addition to mocking the complete object, we can mock just the method we want to test, through &lt;code&gt;patch.object&lt;/code&gt;. In the example below, instead of mocking the entire &lt;code&gt;requests&lt;/code&gt; object, we do this just for its &lt;code&gt;get&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;

&lt;span class="nd"&gt;@mock.patch.object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;get&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_holidays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mocked_get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;mocked_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]))&lt;/span&gt;
    &lt;span class="n"&gt;mocked_get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mocked_response&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;get_holidays&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Christmas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25/12&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="n"&gt;mocked_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_called_once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This option is very useful when we want to maintain the behavior of the rest of the class, simulating the behavior of only specific methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autospeccing
&lt;/h3&gt;

&lt;p&gt;As we've seen, the Mock object is quite flexible, capable of "assuming the identity" of different types of objects. With this flexibility, some pitfalls can occur, such as changing the behavior of a non-existent method of the "mocked" class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, MyProductionClass has the sum_2 method, but when mocking, there was a typo, and the method used is a non-existent method in the class. However, due to the flexible nature of Mock, this operation was allowed, and even though the &lt;code&gt;assert&lt;/code&gt; is returning true, the test is not simulating the behavior correctly because it is being used in a method that does not exist in the original class.&lt;/p&gt;

&lt;p&gt;To prevent this type of problem, we use &lt;code&gt;autospeccing&lt;/code&gt;, which is nothing more than forcing the Mock instance to follow the specification of its real object.&lt;/p&gt;

&lt;p&gt;There are different ways to use it, one of which is represented in the example below, where we specify which specification (spec) the Mock should follow. In this case, it's the specification of the &lt;code&gt;MyProductionClass&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MyProductionClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# speccing the MyProductionClass
&lt;/span&gt;&lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;my_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
raise AttributeError(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mock object has no attribute %r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; % name)
AttributeError: Mock object has no attribute &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sum2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;. Did you mean: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sum_2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;?
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, an AttributeError is raised, specifying that the class does not have the &lt;code&gt;sum2&lt;/code&gt; method, but rather the &lt;code&gt;sum_2&lt;/code&gt;, which is the true method.&lt;/p&gt;

&lt;p&gt;The different ways to use &lt;code&gt;autospeccing&lt;/code&gt; can be found in the &lt;a href="https://docs.python.org/3/library/unittest.mock.html#autospeccing"&gt;documentation&lt;/a&gt;. This is a very useful way to prevent various errors during test writing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Course conclusion
&lt;/h3&gt;

&lt;p&gt;It's a much more extensive course than the first one, covering practically all topics related to the Mock object. Although all the course content can also be found in the documentation, I still found the course quite interesting for synthesizing various topics in a way that facilitates the understanding of the student.&lt;/p&gt;

&lt;p&gt;However, I still missed the following two topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MagicMock&lt;/li&gt;
&lt;li&gt;AsyncMock&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a great course for those who are starting to write tests in Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test-Driven Development With pytest
&lt;/h2&gt;

&lt;p&gt;This was the course I was most excited about, as I work with TDD daily, and unfortunately, it was my biggest disappointment.&lt;/p&gt;

&lt;p&gt;I won't dwell on the course content because TDD was never covered. The course is basically the instructor writing the test and then fully implementing the methods of the class without concern for the red-green-refactor cycle and other TDD-related practices. The content is quite shallow and covers pytest only superficially.&lt;/p&gt;

&lt;p&gt;Although it is very short and you can finish it in just a few hours in front of the computer, it is not worth it if you are interested in learning only TDD because it is not covered here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overall Conclusion
&lt;/h2&gt;

&lt;p&gt;The first two courses I presented are quite interesting for starting with automated testing in Python, especially the second one, which is quite comprehensive and covers a standard library of the language.&lt;/p&gt;

&lt;p&gt;With just the first two courses, you can already navigate on your own in learning and improving your testing skills. Although they are good content, you can't rely solely on them; you need to research more and continue to specialize to become a good test writer.&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, the courses are quite technical, presenting the tools and how to use them. Although I felt the lack of topics on how to write good tests, I understand that it was not their intention, as their goal was to simply introduce the frameworks and not teach how to write good tests.&lt;/p&gt;

&lt;p&gt;Regarding the last course, I was greatly disappointed. Not only because the content is weak, but also because people believe that TDD is just writing tests and then the complete production code, instead of the creative process that I believe it should be.&lt;/p&gt;

</description>
      <category>python</category>
      <category>testing</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Apache Kafka: What is and how it works</title>
      <dc:creator>joaosczip</dc:creator>
      <pubDate>Tue, 02 Mar 2021 02:33:10 +0000</pubDate>
      <link>https://dev.to/joaosczip/apache-kafka-what-is-and-how-it-works-gf9</link>
      <guid>https://dev.to/joaosczip/apache-kafka-what-is-and-how-it-works-gf9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When we start to study &lt;a href="https://martinfowler.com/articles/microservices.html" rel="noopener noreferrer"&gt;microservices&lt;/a&gt;, many different concepts, patterns, protocols, and tools are presented to us, like &lt;strong&gt;Messaging&lt;/strong&gt;, &lt;strong&gt;AMQP&lt;/strong&gt;, &lt;strong&gt;RabbitMQ&lt;/strong&gt;, &lt;strong&gt;Event-sourcing&lt;/strong&gt;, &lt;strong&gt;gRPC&lt;/strong&gt;, &lt;strong&gt;CQRS&lt;/strong&gt;, and many others. Among so many different words, there is one that always caught my attention and I always wanted to start studying it, the Apache Kafka.&lt;/p&gt;

&lt;p&gt;The problem is that people always have a misunderstanding about what Kafka really is and is very common to see people talking about it like it as if it were just another messaging system. In fact, you can do that, but use Kafka &lt;strong&gt;only&lt;/strong&gt; for that may be a waste of resources.&lt;/p&gt;

&lt;p&gt;For that, my goal with this article is to explain how Kafka works and why you may need to use it in your projects. I’ll start presenting the principal concepts, explain why it’s not just a messaging system, I hope that it may help people that are entering this world, as I’m.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Apache Kafka?
&lt;/h2&gt;

&lt;p&gt;If you enter the &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Kafka website&lt;/a&gt;, you’ll find the definition of it right on the first page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A distributed streaming platform&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is an “A distributed streaming platform”? First, we need to define what is a stream. For that, I have a definition that made me really understand it: Streams are just infinite data, data that never end. It just keeping arriving, and you can process it in real-time.&lt;/p&gt;

&lt;p&gt;And distributed? Distributed means that Kafka works in a cluster, each node in the cluster is called &lt;strong&gt;Broker&lt;/strong&gt;. Those brokers are just servers executing a copy of apache Kafka.&lt;/p&gt;

&lt;p&gt;So, basically, &lt;strong&gt;Kafka is a set of machines working together to be able to handle and process real-time infinite data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;His distributed architecture is one of the reasons that made Kafka so popular. The Brokers is what makes it so resilient, reliable, scalable, and fault-tolerant. That’s why Kafka is so performer and secure.&lt;/p&gt;

&lt;p&gt;But why there is this misconception that Kafka is just another messaging system? To respond to that answer, we need first to explain how messaging works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Messaging
&lt;/h2&gt;

&lt;p&gt;Messaging, very briefly, it’s just the act to send a message from one place to another. It has three principal actors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Producer&lt;/strong&gt;: Who produces and send the messages to one or more queues;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue&lt;/strong&gt;: A buffer data structure, that receives (from the producers) and delivers messages (to the consumers) in a FIFO (First-In-First-Out) way. When a message is delivered, it’s removed forever from the queue, there’s no chance to get it back;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer&lt;/strong&gt;: Who is subscribed to one or more queues and receives their messages when published.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that is it, this is how the messaging works (&lt;strong&gt;very briefly&lt;/strong&gt;, there’s a lot more). As you can see there’s nothing about streams, real-time, cluster (depending on what tool you chose, you can use a cluster too, but it’s not native, like Kafka).&lt;/p&gt;

&lt;h2&gt;
  
  
  Kafka Architecture
&lt;/h2&gt;

&lt;p&gt;Now that we know how messaging works, let’s get dive into the Kafka world. In Kafka, we also have the &lt;strong&gt;Producers&lt;/strong&gt; and &lt;strong&gt;Consumers&lt;/strong&gt;, they work in a very similar way that they work in the messaging, both producing and consuming messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pnn60951tl057o9g0d7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pnn60951tl057o9g0d7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://www.cloudkarafka.com/blog/2016-11-30-part1-kafka-for-beginners-what-is-apache-kafka.html" rel="noopener noreferrer"&gt;https://www.cloudkarafka.com/blog/2016-11-30-part1-kafka-for-beginners-what-is-apache-kafka.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see it is very similar to what we’ve discussed about messaging, but here we don’t have the &lt;strong&gt;Queue&lt;/strong&gt; concept, instead, we have the concept of &lt;strong&gt;Topics&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Topic&lt;/strong&gt; is a very specific type of data stream, it’s very similar to a Queue, it receives and delivers messages as well, but there are some concepts that we need to understand about topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A topic is divided into &lt;strong&gt;partitions&lt;/strong&gt;, each topic can have one or more partitions and we need to specify that number when we're creating the topic. You can imagine the topic as a folder in the operation system and each folder inside her as a partition;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If we don’t give any key to a message when we’re producing it, by default, the producers will send the message in a &lt;strong&gt;round-robin&lt;/strong&gt; way, each partition will receive a message (even if they are sent by the same producer). Because of that, we aren’t able to guarantee the delivery order at the partition level, if we want to send a message always to the same partition, we need to give a &lt;strong&gt;key&lt;/strong&gt; to our messages. This will ensure that the message will always be sent to the same partition;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each message will be stored in the broker disk and will receive an offset (unique identifier). This offset is unique at the partition level, each partition has its owns &lt;strong&gt;offsets&lt;/strong&gt;. That is one more reason that makes Kafka so special, it stores the messages in the disk (like a database, and in fact, Kafka is a database too) to be able to recover them later if necessary. Different from a messaging system, that the message is deleted after being consumed;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The producers use the offset to read the messages, they read from the oldest to the newest. In case of consumer failure, when it recovers, will start reading from the last offset.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkeytdy7ia14cyd037vvb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkeytdy7ia14cyd037vvb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;The partitions of a topic — &lt;a href="https://d2h0cx97tjks2p.cloudfront.net/blogs/wp-content/uploads/sites/2/2018/07/Kafka-Topic-Partitions-Layout.png" rel="noopener noreferrer"&gt;https://d2h0cx97tjks2p.cloudfront.net/blogs/wp-content/uploads/sites/2/2018/07/Kafka-Topic-Partitions-Layout.png&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Brokers
&lt;/h2&gt;

&lt;p&gt;As said before, Kafka works in a distributed way. A Kafka cluster may contain many brokers as needed.&lt;/p&gt;

&lt;p&gt;Each broker in a cluster is identified by an ID and contains at least one partition of a topic. To configure the number of the partitions in each broker, we need to configure something called &lt;strong&gt;Replication Factor&lt;/strong&gt; when creating a topic. Let’s say that we have three brokers in our cluster, a topic with three partitions and a Replication Factor of three, in that case, each broker will be responsible for one partition of the topic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkrb6yj7lr83oizuhsk8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkrb6yj7lr83oizuhsk8s.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;The Replication Factor — &lt;a href="https://fullcycle.com.br/apache-kafka-trabalhando-com-mensageria-e-real-time/" rel="noopener noreferrer"&gt;https://fullcycle.com.br/apache-kafka-trabalhando-com-mensageria-e-real-time/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the above image, &lt;strong&gt;Topic_1&lt;/strong&gt; has three partitions, each broker is responsible for a partition of the topic, so, the Replication Factor of the Topic_1 is three.&lt;/p&gt;

&lt;p&gt;It’s very important that the number of the partitions match the number of the brokers, in this way, each broker will be responsible for a single partition of the topic.&lt;/p&gt;

&lt;p&gt;To ensure the reliability of the cluster, Kafka enters with the concept of the &lt;strong&gt;Partition Leader&lt;/strong&gt;. Each partition of a topic in a broker is the leader of the partition and can exist only one leader per partition. The leader is the only one that receives the messages, their &lt;strong&gt;replicas&lt;/strong&gt; will just sync the data (they need to be in-sync to that). It will ensure that even if a broker goes down, his data won’t be lost, because of the replicas.&lt;/p&gt;

&lt;p&gt;When a leader goes down, a replica will be automatically elected as a new leader by &lt;a href="https://zookeeper.apache.org/" rel="noopener noreferrer"&gt;Zookeeper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fae4chs5pc599yetghkg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fae4chs5pc599yetghkg4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;Partition Leader — &lt;a href="https://www.educba.com/kafka-replication/" rel="noopener noreferrer"&gt;https://www.educba.com/kafka-replication/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the above image, &lt;strong&gt;Broker 1&lt;/strong&gt; is the leader of &lt;strong&gt;Partition 1&lt;/strong&gt; of &lt;strong&gt;Topic 1&lt;/strong&gt; and has a replica in &lt;strong&gt;Broker 2&lt;/strong&gt;. Let’s say that &lt;strong&gt;Broker 1&lt;/strong&gt; dies, when it happens, Zookeeper will detect that change and will make &lt;strong&gt;Broker 2&lt;/strong&gt; the leader of &lt;strong&gt;Partition 1&lt;/strong&gt;. This is what makes the distributed architecture of Kafka so powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Producers
&lt;/h2&gt;

&lt;p&gt;Just like in the messaging world, Producers in Kafka are the ones who produce and send the messages to the topics.&lt;/p&gt;

&lt;p&gt;As said before, the messages are sent in a &lt;strong&gt;round-robin&lt;/strong&gt; way. Ex: Message 01 goes to partition 0 of Topic 1, and message 02 to partition 1 of the same topic. It means that we can’t guarantee that messages produced by the same producer will always be delivered to the same topic. We need to specify a key when sending the message, Kafka will generate a hash based on that key and will know what partition to deliver that message.&lt;/p&gt;

&lt;p&gt;That hash takes into consideration the number of the partitions of the topic, that’s why that number cannot be changed when the topic is already created.&lt;/p&gt;

&lt;p&gt;When we are working with the concept of messages, there’s something called &lt;strong&gt;Acknowledgment&lt;/strong&gt; (ack). The ack is basically a confirmation that the message was delivered. In Kafka, we can configure this ack when producing the messages. There are three different levels of configuration for that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ack = 0&lt;/strong&gt;: When we configure the ack = 0, we’re saying that we don’t want to receive the ack from Kafka. In case of broker failure, the message will be lost;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ack = 1&lt;/strong&gt;: This is the default configuration, with that we’re saying that we want to receive an ack from the leader of the partition. The data will only be lost if the leader goes down (still there’s a chance);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ack = all&lt;/strong&gt;: This is the most reliable configuration. We are saying that we want to not only receive a confirmation from the leader but from their replicas as well. This is the most secure configuration since there’s no data loss. Remembering that the replicas need to be in-sync (ISR). If a single replica isn’t, Kafka will wait for the sync to send back de ack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmosl19ozkvzs22amn6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmosl19ozkvzs22amn6q.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;ack = all — &lt;a href="https://static.javatpoint.com/tutorial/kafka/images/apache-kafka-producer5.png" rel="noopener noreferrer"&gt;https://static.javatpoint.com/tutorial/kafka/images/apache-kafka-producer5.png&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Consumers and Consumers Groups
&lt;/h2&gt;

&lt;p&gt;Consumers are applications subscribed to one or more topics that will read messages from there. They can read from one or more partitions.&lt;/p&gt;

&lt;p&gt;When a consumer reads from just one partition, we can ensure the order of the reading, but when a single consumer reads from two or more partitions, it will read in parallel, so, there’s no guarantee of the reading order. A message that came later can be read before another that came earlier, for example.&lt;/p&gt;

&lt;p&gt;That’s why we need to be careful when choosing the number of partitions and when producing the messages.&lt;/p&gt;

&lt;p&gt;Another important concept of Kafka is the Consumer Groups. It’s really important when we need to scale the messages reading.&lt;/p&gt;

&lt;p&gt;It becomes very costly when a single consumer needs to read from many partitions, so, we need o load-balancing this charge between our consumers, this is when the consumer groups enter.&lt;/p&gt;

&lt;p&gt;The data from a single topic will be load-balancing between the consumers, with that, we can guarantee that our consumers will be able to handle and process the data.&lt;/p&gt;

&lt;p&gt;The ideal is to have the same number of consumers in a group that we have as partitions in a topic, in this way, every consumer read from only one. When adding consumers to a group, you need to be careful, if the number of consumers is greater than the number of partitions, some consumers will not read from any topic and will stay idle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnukye3w7msrs48vxjnvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnukye3w7msrs48vxjnvv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;Consumer Groups — &lt;a href="https://docs.cloudera.com/cdp-private-cloud-base/latest/kafka-developing-applications/topics/kafka-develop-groups-fetching.html" rel="noopener noreferrer"&gt;https://docs.cloudera.com/cdp-private-cloud-base/latest/kafka-developing-applications/topics/kafka-develop-groups-fetching.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Kafka is one of the most completes and performer tools that we have today. After studying it and get their principal concepts, I realized that is much more than just a messaging system. Your distributed architecture and real-time processing are what make it so adaptable to very different scenarios and use cases.&lt;/p&gt;

&lt;p&gt;With this article, I tried to dive deep into Kafka, presenting their principal concepts to make it easier to understand and bring their differences from the traditional messaging systems.&lt;/p&gt;

&lt;p&gt;Because of the time, I left some important concepts out of this article, like idempotent producers, compression, transactions, etc, but I really hope that this helps you to study and explore more this world.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.cloudkarafka.com/blog/2016-11-30-part1-kafka-for-beginners-what-is-apache-kafka.html" rel="noopener noreferrer"&gt;https://www.cloudkarafka.com/blog/2016-11-30-part1-kafka-for-beginners-what-is-apache-kafka.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://fullcycle.com.br/apache-kafka-trabalhando-com-mensageria-e-real-time/" rel="noopener noreferrer"&gt;https://fullcycle.com.br/apache-kafka-trabalhando-com-mensageria-e-real-time/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.educba.com/kafka-replication/" rel="noopener noreferrer"&gt;https://www.educba.com/kafka-replication/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.javatpoint.com/apache-kafka-producer" rel="noopener noreferrer"&gt;https://www.javatpoint.com/apache-kafka-producer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.cloudera.com/cdp-private-cloud-base/latest/kafka-developing-applications/topics/kafka-develop-groups-fetching.html" rel="noopener noreferrer"&gt;https://docs.cloudera.com/cdp-private-cloud-base/latest/kafka-developing-applications/topics/kafka-develop-groups-fetching.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>microservices</category>
      <category>programming</category>
      <category>bigdata</category>
    </item>
    <item>
      <title>Build a file upload service with NodeJS, Typescript, Clean Architecture and AWS S3</title>
      <dc:creator>joaosczip</dc:creator>
      <pubDate>Fri, 29 Jan 2021 16:19:19 +0000</pubDate>
      <link>https://dev.to/joaosczip/build-a-file-upload-service-with-nodejs-typescript-clean-architecture-and-aws-s3-3h9b</link>
      <guid>https://dev.to/joaosczip/build-a-file-upload-service-with-nodejs-typescript-clean-architecture-and-aws-s3-3h9b</guid>
      <description>&lt;p&gt;In the old days, before that cloud thing become what it’s today, the way that the programs store their files (images, documents, etc) was a little different from now.&lt;/p&gt;

&lt;p&gt;We had our local servers, running our applications locally and any type of file that was uploaded, was also stored in the same server (or not, but still locally) that the application was.&lt;/p&gt;

&lt;p&gt;The problem with that architecture is that it can lead to several problems for our server, especially if the amount of the files that will be stored was meaningful (GB of files for example). The two main problems with that are the storage and the security. The storage could leave our server to become slow and the security, in case of loss of files, there’s no comment, especially if those files are confidential.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyzjjsctmq47ep7rf61z5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyzjjsctmq47ep7rf61z5.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Client-Server architecture with local servers — &lt;a href="https://www.sciencedirect.com/topics/computer-science/client-server-architecture" rel="noopener noreferrer"&gt;https://www.sciencedirect.com/topics/computer-science/client-server-architecture&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Today the scenario is a little different, instead of local servers, we have a lot of cloud providers who provide us several different services, including storage services. In this example, I’ll show you how to create an API with NodeJS, Express and Typescript, to handle and upload files to AWS S3 (Simple Storage Service), also using Clean Architecture, IoC, SOLID principles and multer to handle the form-data that we’ll send.&lt;/p&gt;

&lt;p&gt;I’m assuming that you already have an AWS account and an IAM user with the right permissions to use S3.&lt;/p&gt;
&lt;h2&gt;
  
  
  API Structure
&lt;/h2&gt;

&lt;p&gt;Let’s get started from our domain layer. In NodeJS environments, we don’t have the &lt;a href="https://developer.mozilla.org/pt-BR/docs/Web/API/File" rel="noopener noreferrer"&gt;File Interface&lt;/a&gt; provided for us in the browser, so we need to create it on our own. So, inside the &lt;strong&gt;domain&lt;/strong&gt; folder, let’s create the &lt;strong&gt;models/file.ts&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This interface provides all the information that we need to handle and manipulate the incoming files. It’s very similar to the interface from the browsers.&lt;/p&gt;

&lt;p&gt;And we also need an interface in our domain to represent the response from the file upload action. In our case, it’ll be very simple, just the path from the object in the storage service.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, we can start with our principal use case, the File Upload. Inside &lt;strong&gt;domain&lt;/strong&gt;, let’s create the file &lt;strong&gt;usecases/file-upload.ts&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Remembering that our use case is just the contract. The implementation will be in the &lt;strong&gt;application&lt;/strong&gt; layer. As you can see, the imports are made with the &lt;a href="https://www.npmjs.com/package/tsconfig-paths" rel="noopener noreferrer"&gt;tsconfig-paths&lt;/a&gt;, to be cleaner and flexible to changes.&lt;/p&gt;

&lt;p&gt;When I have absolute knowledge of what I need to implement and what I’ll use to do that, I always start with the domain layer, because it’s the core of our service.&lt;/p&gt;

&lt;p&gt;Getting started with our concrete implementation, in the application layer, let’s create a class that will implement the FIleUpload interface, this class will be responsible to group the received files from the controller and send them to the infra service that will communicate with the AWS SDK.&lt;/p&gt;

&lt;p&gt;Before creating our class, let’s define the protocol for the infra service, we’ll call him &lt;strong&gt;FileUploader&lt;/strong&gt; and place it in the &lt;strong&gt;application/protocols/file-uploader.ts&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, we’ll be able to create our implementation to FileUpload (the use case, not the infra protocol). Our concrete class will be called &lt;strong&gt;RemoteFileUpload&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is a very simple implementation, as you can see, we’re implementing the FileUpload and using &lt;a href="https://www.npmjs.com/package/tsyringe" rel="noopener noreferrer"&gt;tsyringe&lt;/a&gt; as IoC container to inject an implementation of FIleUploader (it’s not created yet).&lt;/p&gt;

&lt;p&gt;We need to add the decorator &lt;strong&gt;@injectable&lt;/strong&gt; to say that all the dependencies of the class will be injected when the application starts. The &lt;strong&gt;@inject&lt;/strong&gt; decorator receives a token that we want to resolve, in our case, the FileUploader.&lt;/p&gt;

&lt;p&gt;Now we need to create the class that will implement the FIleUploader and communicates with the &lt;a href="https://www.npmjs.com/package/aws-sdk" rel="noopener noreferrer"&gt;aws-sdk&lt;/a&gt;. This class will be in the infra layer, so, let’s create the &lt;strong&gt;infra/aws-file-uploader.ts&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This class uses the aws-sdk library (don’t forget to install it) to communicate with the AWS S3 and make the uploads. It can send just a single or a list of files (one per time). Here, the implementation isn’t the most important, pay attention to the architecture details, the way I choose to implement was just what meets my needs.&lt;/p&gt;

&lt;p&gt;As you can see, I’m using some config file to store the bucket name and the region, this file uses the env variables that I defined in my docker-compose (you can define in your .env if running locally).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Remember that in the actual version of the sdk there is no more need to fill the aws secret and key when instantiating any service, it’ll look for those values in your environment.&lt;/p&gt;

&lt;p&gt;With our application and infra layer completes, it’s time to create the controller that will handle the requests and will call the use case with the files.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The controller also uses the IoC container to receive a FileUpload instance, which in your case will be the &lt;strong&gt;RemoteFileUpload&lt;/strong&gt;. I won’t get deep into the details of the &lt;strong&gt;HttpRequest&lt;/strong&gt; and &lt;strong&gt;HttpResponse&lt;/strong&gt; types, those are just to abstract the Express response and request parameters. The interface that the controller was implementing, have just the method handle, that will receive the request and return a response.&lt;/p&gt;

&lt;p&gt;With the controller created, let’s create our route and call our controller inside it. Another thing to notice about the route is that we need to use the &lt;a href="https://www.npmjs.com/package/multer" rel="noopener noreferrer"&gt;multer&lt;/a&gt; to handle the files on the request (because we can’t send files on JSON).&lt;/p&gt;

&lt;p&gt;Because multer has his own type of File, we created a middleware to map the multer file to our own File interface.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, we first added the &lt;strong&gt;upload&lt;/strong&gt; middleware from multer and after that, our own &lt;strong&gt;fileHandler&lt;/strong&gt; middleware, so, when passing the request to the controller, the files will be mapped to the format that we expect and inside the body.&lt;/p&gt;

&lt;p&gt;Now, the rest is just configuration. We need to configure our service startup, to use express and also the IoC container with the map of &lt;strong&gt;contract =&amp;gt; implementation&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Remember to put the import of the IoC inside your entrypoint.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I hope that this tutorial will help you clarify something, like handling files with express, IoC container, usage of AWS SDK and files upload.&lt;/p&gt;

&lt;p&gt;The goal of this article was to explain how we can create a very robust and flexible architecture even in cases that we need to communicate with external services and/or use third-party libraries. The focus wasn’t on the Clean Architecture itself, but what we can do using the principles behind her and some SOLID principles.&lt;/p&gt;

&lt;p&gt;I’ll leave the link to the repository &lt;a href="https://github.com/joaosczip/photo-upload-ms" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you are interested to see how the project got.&lt;/p&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>aws</category>
    </item>
    <item>
      <title>Clean Architecture — A little introduction</title>
      <dc:creator>joaosczip</dc:creator>
      <pubDate>Thu, 13 Aug 2020 22:05:48 +0000</pubDate>
      <link>https://dev.to/joaosczip/clean-architecture-a-little-introduction-4ag6</link>
      <guid>https://dev.to/joaosczip/clean-architecture-a-little-introduction-4ag6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;With the constant evolution in the software development process and the growing adoption of different frameworks, is becoming very common developers getting comfortable with the structures provided by these tools and leaving aside some principles of good software development. We need to keep in mind that these tools are just the path and not the end. Our software needs to be more “Domain Oriented Software” and less “Framework Oriented Software”.&lt;/p&gt;

&lt;p&gt;That’s not a criticism with the frameworks and libraries adoptions, they really need to be used, there are a lot of wonderful projects that are here to help us, but we should use them in a way that these tools are adapted to our solution, and not the opposed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our domain does not need to know what web framework or what database system we are using&lt;/strong&gt;, these things are just plugins that we may define later.&lt;/p&gt;

&lt;p&gt;Thinking about this problem, many solutions have been created and one of these is the “Clean Architecture”, presented by Uncle Bob.&lt;/p&gt;

&lt;p&gt;That post will give you a little introduction about Clean Architecture, your main concepts, and a way to implement it, giving us an example of an application build with ReactJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean Architecture
&lt;/h2&gt;

&lt;p&gt;The main purpose of the Clean Architecture is the Dependency Rule, this rule is all about the direction that our dependencies should point to, that is, always to the high-level policies.&lt;/p&gt;

&lt;p&gt;The high-level policies are defined as the core of our application, the components that are independent of any programming language or technology, the policies that only need to change when our domain changes, that is, only in very specific cases.&lt;/p&gt;

&lt;p&gt;In contrast, the less specific the component is, the lower the level will be. Here we may put the repositories that connect to our database, the HTTP client that made requests, the presentation layer responsible for the UI, and some components that need to talk with third party libraries for example.&lt;/p&gt;

&lt;p&gt;We can see that the low-level policies are responsible for things that aren’t specific to our domain but specific for our application, and the application is just the way we choose to solve our domain problem.&lt;/p&gt;

&lt;p&gt;The figure below exemplifies how the Dependency Rule works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuc1gd2ht58d9yqn29mhz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuc1gd2ht58d9yqn29mhz.jpg" alt="Figure 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you may see, all the externals agents point in the same direction, and that pattern may give some benefits to us.&lt;/p&gt;

&lt;p&gt;Our entities and use cases don’t have any external world dependency, the only concern that they have is about the domain itself.&lt;/p&gt;

&lt;p&gt;So, if we need to change any external agent implementation like an HTTP client, we don’t need to change anything in our use cases, just in the HTTP client concrete class implementation.&lt;/p&gt;

&lt;p&gt;That’s another crucial point in the Clean Architecture, all cross-layer communication is made through solid interfaces. Dependency Inversion has a crucial role in that design, as a matter of fact, we only can get the most of Clean Architecture with we know how to implement all the SOLID principles correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let’s say we have a use case responsible to send a picture to the server. To accomplish that use case, we decided to build a front-end client application with React + Typescript.&lt;/p&gt;

&lt;p&gt;We also decided to follow some implementation of the Clean Architecture structure proposal, so, our application will have the following layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain Layer&lt;/strong&gt;: The Domain Layer is the most high-level policy that we have, is where we define the entities and the use cases. We don’t have any concrete class in that layer, only interfaces. All the use case implementations will be in the next layer, the Data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Layer&lt;/strong&gt;: Right behind the Domain Layer, this layer is responsible to implement all the use cases and to define protocols (interfaces) that use case needs. The protocols defined in that layer will be implemented on the next, the Infra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infra Layer&lt;/strong&gt;: That Layer will implement the protocols defined in the Data, normally, those implementations are designed to the external world communications, such as database operations, HTTP requests, third-party libraries, and so on. If we think of a client application, like a React app, in that layer we have the HTTP clients, for example.&lt;/p&gt;

&lt;p&gt;Looking with more attention to the last figure, we can see that the Infra Layer belongs to the outer circle, in that circle we do have concrete implementations of libraries and frameworks, it is the most low-level policy that we have, those that aren’t a domain-specific problem.&lt;/p&gt;

&lt;p&gt;In that circle, we also have the &lt;strong&gt;Presentation Layer&lt;/strong&gt;, responsible for the UI. Here, in our example, that layer will implement all the React code.&lt;/p&gt;

&lt;p&gt;Separating the things in that way, we can see that our core code is completely independent of the library that we choose. We only see the React in one layer, only making what it is designed to do, leaving the business code to other layers. Isolating the app like that, we have many more benefits than coupling all the domain code in our UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Following our example, first, we need a use case responsible to send images to a server. Let’s call him SendImage.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, our use case is just an interface that defines a method send and returns a Promise of a DetectedImage (a specific entity to our domain).&lt;/p&gt;

&lt;p&gt;Now that we have our use case, we need an implementation for him, let’s create a RemoteSendImage in our Data Layer.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Some important things to notice about that implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the class constructor, via dependency injection, we are defining that this class needs an implementation of a HttpPostClient, and a URL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Those dependencies are specific to that implementation. If we have another implementation that does not send the image over HTTP, the dependencies will be another.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, that we defined that we need a HttpPostClient protocol, let’s create in the Data Layer too.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Just like our use case, that protocol is just an interface that defines a post method. For that implementation, the axios library was chosen, now we create an AxiosHttpClient concrete class that implements the HttpPostClient.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;An important thing to notice about that implementation is his interface. Why we didn’t create a more generic interface, instead of one that only knows POST request (HttpPostClient)?&lt;/p&gt;

&lt;p&gt;At that moment, we only need to make POST requests, our use case implementation doesn’t tell not about any GET or PUT requests. So, following the Interface Segregation Principle, we make an extremely cohesive interface, that only knows the method that we need at the moment. If in the future we need to make a GET request for example, we define a protocol for that and make our AxiosHttpClient implement that interface too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Presentation Layer
&lt;/h2&gt;

&lt;p&gt;Now it’s the time that React comes in. In our Presentation Layer, we will define a functional component that receives a SendImage use case via dependency inversion in their props.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;There are some important things to notice here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A React functional component that only used hooks for your internal logic;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The fact that the component receives an implementation of SendImage in his props is one of the things that make the app structure more flexible;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The first advantage of this structure is that our UI component doesn’t know anything about sending an image to the server, he only needs someone that knows how to the that. Making your only concern about the UI. That’s the Single Responsibility Principle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another advantage is that if in the future we decide to send the images over another protocol, we only change the use case implementation, the UI will not even notice that change. With the help of the polymorphism, we can change the implementation easily (Liskov Substitution).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, our folder structure will be like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2fmjj2jpih2u6409leu7.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2fmjj2jpih2u6409leu7.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Unlike most of the examples that we can find on the internet, this implementation provides a very different approach, where the focus of our UI is only the presentation logic. We were able to create a component completely independent of our domain logic and vice versa.&lt;/p&gt;

&lt;p&gt;If we have a use case that needs to send an image to the server, it doesn’t matter if we use a page created in React, Angular, or Vue, our domain is not concerned with that, it is only concerned with the core of the application. Our domain needs to work in the same way regardless of the framework or libraries we are using. If a more delicate exchange is ever needed, we can do it without having to invest a lot of time in it.&lt;/p&gt;

&lt;p&gt;From the moment that we have a more flexible and robust architecture, in addition to being strongly abstracted, we are able to observe in practice the benefits of object orientation and its principles being fulfilled. At first, it may seem too much work, and it is indeed, because it is necessary to create many protocols and implementations, however, in the long run, it is a trade-off that is really worthwhile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React course with TDD and SOLID (PT-BR)&lt;/strong&gt;: &lt;a href="https://www.udemy.com/course/react-com-mango/" rel="noopener noreferrer"&gt;https://www.udemy.com/course/react-com-mango/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Github repository for this article&lt;/strong&gt;: &lt;a href="https://github.com/joaosczip/clean_react" rel="noopener noreferrer"&gt;https://github.com/joaosczip/clean_react&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>oop</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Applying Open-Closed Principle with Decorator Pattern in Typescript</title>
      <dc:creator>joaosczip</dc:creator>
      <pubDate>Thu, 06 Aug 2020 16:17:21 +0000</pubDate>
      <link>https://dev.to/joaosczip/applying-open-closed-principle-with-decorator-pattern-in-typescript-242j</link>
      <guid>https://dev.to/joaosczip/applying-open-closed-principle-with-decorator-pattern-in-typescript-242j</guid>
      <description>&lt;p&gt;That's the first time that I'm writing a post in english, so any feedback that you may give to me will be very important. I'll be grateful.&lt;/p&gt;

&lt;h1&gt;
  
  
  Preface
&lt;/h1&gt;

&lt;p&gt;In the recent days some of my study focus are the SOLID principles, Clean Architecture and some releated topics like Design Patterns, and I need to confess that I was using the OOP techiniques in the wrong way since college, I realised that what I was writing was just procedural code separated in different files with classes and methods, there wasn't a single advantage by using OOP like that, so I decided to change.&lt;/p&gt;

&lt;h1&gt;
  
  
  Design Principles
&lt;/h1&gt;

&lt;p&gt;Every paradigm has its own principles, in the OOP world those principles are the SOLID (there are a few more, but those are the most famous and used). So what this means, these SOLID keywords? They stand for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt;ingle Responsability;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O&lt;/strong&gt;pen-Closed;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L&lt;/strong&gt;iskov Substitution;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt;nterface Segregation;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D&lt;/strong&gt;ependency Inversion;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, if you build your application following all those principles, your codebase will be more flexible, abstracted and maintainable, the evolution of the software will be less painful and costly, giving you more time to expend implementing new things.&lt;/p&gt;

&lt;h1&gt;
  
  
  Open-Closed Principle
&lt;/h1&gt;

&lt;p&gt;The Open-Closed Principle says that our classes must be open for expansions and closed for changes. Basically, we must be able to change the implementation behavior on execution-time, and to reach that,  we don't need to change the class codebase, we just need the help of composition.&lt;/p&gt;

&lt;p&gt;There is a famous dictation that says that we need to prefer composition over inheritance, and this is really important. There are some issues when we decide to use inheritance, the first is that we're breaking the OOP foundation of encapsulation, because the children knows everything about the parent. The second is the static inheritance, we can't change the behavior of the children even in execution-time, we need to change the codebase itself to be able to change the behavior, breaking the Open-Closed Principle.&lt;/p&gt;

&lt;p&gt;When we have composition, we no longer have the "is" relationship (Ex: SavingsAccount &lt;strong&gt;is&lt;/strong&gt; an Account) and we passed to have the "has" relationship (Ex: AuthorizationClient &lt;strong&gt;has&lt;/strong&gt; a HttpClient), so, following the example, AuthorizationClient behaves like a normal HttpClient, but he can change your default behavior, adding an authorization header for example.&lt;/p&gt;

&lt;h1&gt;
  
  
  Example
&lt;/h1&gt;

&lt;p&gt;Imagine the following scenario, let's say we have a front-end client application written in React, we're consuming an API and we need to pass an authentication token (a jwt for example). We decide to create an interface responsible for send HTTP requests, so, in the data layer we create our HttpPostClient protocol (Only POST requests, following the Interface Segregation principle, subject for another post).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9ti7rsj3ifb1ff101z3b.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9ti7rsj3ifb1ff101z3b.PNG" alt="Alt Text" width="541" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, we create an implementation for this protocol based in the axios library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft75mrw120rdo8wlhdssn.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft75mrw120rdo8wlhdssn.PNG" alt="Alt Text" width="477" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have our protocol (HttpPostClient) and our implementation (AxiosHttpClient), why we can't just pass the authorization header normally in the method call? We need to think that this header needs to be passed in many requests and will be always the same: Capture the token from the localStorage or from another service and pass to the method that will do the request. If we just copy &amp;amp; paste this implementation, we will be breaking the DRY (Don't Repeat Yourself) principle, so we need to think a smart way to do that. That's where the Decorator Pattern comes in.&lt;/p&gt;

&lt;p&gt;The Decorator Pattern is basically a wrapper for an object. This wrapper must have the same type of the wrapped object i.e. implement the same interface and because of that, they can be exchanged in a way that the client class don't notice that change (Liskov Substitution). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal of this pattern is to add a behavior to the decorated object.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Going back to our example, we need a Decorator that implements the HttpPostClient interface and add the desired behavior to our AxiosHttpClient without changing the class implementation.&lt;/p&gt;

&lt;p&gt;This Decorator class will be called AuthorizationHttpPostClientDecorator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzwrrav0vt9jau1vuz1v6.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzwrrav0vt9jau1vuz1v6.PNG" alt="Alt Text" width="665" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some important things to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our Decorator class has the same interface of the decorated object.&lt;/li&gt;
&lt;li&gt;He receives the wrapped object on the constructor (Dependency Inversion principle)&lt;/li&gt;
&lt;li&gt;Runs some logic and them calls the method from the decorated object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's an example of how we can add behavior to an class without change your implementation code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Whenever we choose a new program paradigm to work with, we need to be aware of his foundations and principles, only with that knowledge we will be able to deeply understand how to use that paradigm correctly and get the most of it.&lt;/p&gt;

&lt;p&gt;In this example I tried to demonstrate the Open-Closed principle in an easy way, with an easy example, so that you can realize its importance. I choose the decorator pattern because your application of the Open-Closed is one of the most common, however I could also implement the Proxy Pattern, he is also an structural one and work in a very similar way.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>react</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
