<?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: Andrew Piterov</title>
    <description>The latest articles on DEV Community by Andrew Piterov (@andrewpiterov).</description>
    <link>https://dev.to/andrewpiterov</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%2F238614%2Fb3c8a8f1-79db-4e21-9b9f-d04f09cd387e.jpeg</url>
      <title>DEV Community: Andrew Piterov</title>
      <link>https://dev.to/andrewpiterov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andrewpiterov"/>
    <language>en</language>
    <item>
      <title>Readable Unit Tests in Dart/Flutter</title>
      <dc:creator>Andrew Piterov</dc:creator>
      <pubDate>Fri, 20 May 2022 11:59:11 +0000</pubDate>
      <link>https://dev.to/andrewpiterov/readable-unit-tests-in-dartflutter-2b37</link>
      <guid>https://dev.to/andrewpiterov/readable-unit-tests-in-dartflutter-2b37</guid>
      <description>&lt;p&gt;In this article, I will show you how to write more readable and expressive unit tests. And, maybe, you feel like a writer of an interesting poem, not a boring and tedious code.&lt;/p&gt;

&lt;p&gt;I won't go into too much detail on TDD and BDD. I assume that you are already familiar with or at least heard what these techniques are. If not, then please take a look at the &lt;a href="https://www.youtube.com/watch?v=FWra0ORVios" rel="noopener noreferrer"&gt;TDD video lesson here&lt;/a&gt; and about the BDD video lesson here or the video version of the article&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/1j9UoOX7Iqs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is BDD?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;BDD&lt;/strong&gt; or &lt;strong&gt;Behaviour Driven Development&lt;/strong&gt; is a technique in application development when development is driven (or dictated) by the &lt;strong&gt;behavior&lt;/strong&gt; of the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BDD&lt;/strong&gt; - is an extension for &lt;strong&gt;TDD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TDD&lt;/strong&gt; (&lt;strong&gt;Test-driven development&lt;/strong&gt;) means &lt;em&gt;"writing tests before implementation"&lt;/em&gt;. And &lt;strong&gt;BDD&lt;/strong&gt; is added that tests (or scenarios) should describe &lt;em&gt;"behavior of the system"&lt;/em&gt;, in our case in unit tests, the behavior of a unit (class or function).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use BDD?
&lt;/h2&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%2F4xnsd5beefy9ll6t51bn.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%2F4xnsd5beefy9ll6t51bn.png" alt="What is a BDD"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every company has at least two teams. The first is the business team (Business Owners, analysts, and others who are not technical specialists), and the second is the development (and maybe testers) team. And in order to bridge the gap between them in understanding - "The business team understands what the development team is doing", and "the development team clearly understands what the business requires" they need a "common" language that is understandable for all parts of the team, even non-programmers and at the same time structured enough for automation.&lt;/p&gt;

&lt;p&gt;So they use &lt;strong&gt;BDD&lt;/strong&gt; and its scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  BDD style
&lt;/h2&gt;

&lt;p&gt;What do I mean by &lt;strong&gt;more readable&lt;/strong&gt; tests?&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;BDD style&lt;/strong&gt; of scenarios (or tests).&lt;/p&gt;

&lt;p&gt;For example, below is the scenario for &lt;code&gt;PNL Calculator&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Given 1000 coins with a total investment of $1000
When coin price raise up to $2
Then PNL % should be 100%
  And PNL value should be $1000
  And holding value should be $2000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BDD scenarios (tests) are written according to the following pattern &lt;strong&gt;GIVEN-WHEN-THEN&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GIVEN&lt;/strong&gt; - initial state or input parameters, i.e., we had 1000 coins and spent $1,000 to buy them, or the price of one coin was $1;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WHEN&lt;/strong&gt; - the action we are testing, i.e., the price of the coin has doubled, and the calculator should calculate the new PNL values ​​for us;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;THEN&lt;/strong&gt; - output parameters or final state, i.e., new values, we have profit, loss, or nothing has changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Three parts of unit tests
&lt;/h2&gt;

&lt;p&gt;Next, we need to highlight three parts related to unit tests. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the code of the tests themselves;&lt;/li&gt;
&lt;li&gt;report on success or failure;&lt;/li&gt;
&lt;li&gt;error message in case of a failed test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these parts is very important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the &lt;strong&gt;test code&lt;/strong&gt; is written earlier, then in a couple of weeks, it will be easier to understand the code for you, or a new developer will quickly understand what the test is about, or even a tester will be able to write a unit test himself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report&lt;/strong&gt; - can be a "living documentation" that describes how the program works and can be read by any team member, even a non-technical person.&lt;/li&gt;
&lt;li&gt;If the &lt;strong&gt;error message&lt;/strong&gt; clearly explains the cause of the error, and understands the context, then fixing the test will be faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will improve each of these parts now.&lt;/p&gt;

&lt;h2&gt;
  
  
  PNL Calculator
&lt;/h2&gt;

&lt;p&gt;Using the &lt;code&gt;PNL Calculator&lt;/code&gt; as an example, we will describe its behavior in unit tests.&lt;/p&gt;

&lt;p&gt;Imagine that we need to write tests for three cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when the price of the coin has risen - profit;&lt;/li&gt;
&lt;li&gt;when the price of the coin has decreased - loss;&lt;/li&gt;
&lt;li&gt;when the price of the coin has not changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BDD scenario for profit case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Given 1000 coins with a total investment of $1000
When coin price raise up to $2
Then PNL % should be 100%
  And PNL value should be $1000
  And holding value should be $2000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A unit test might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Given 1000 coins with a total investment of &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000 '&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;coinAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;totalInvestment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;When coin price raise up to &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;2'&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="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;PnlCalculatorResult&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PnlCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;coinAmount:&lt;/span&gt; &lt;span class="n"&gt;coinAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;totalInvestments:&lt;/span&gt; &lt;span class="n"&gt;totalInvestment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;currentPrice:&lt;/span&gt; &lt;span class="mi"&gt;2&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="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Then PNL % should be 100%'&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="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;    And PNL value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000'&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="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;    And holding value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;2000'&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="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the output we would get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;✓ Given 1000 coins with a total investment of &lt;span class="nv"&gt;$1000&lt;/span&gt;  
When coin price raise up to &lt;span class="nv"&gt;$2&lt;/span&gt; 
Then PNL % should be 100%
✓ Given 1000 coins with a total investment of &lt;span class="nv"&gt;$1000&lt;/span&gt;  
When coin price raise up to &lt;span class="nv"&gt;$2&lt;/span&gt; 
    And PNL value should be &lt;span class="nv"&gt;$1000&lt;/span&gt;
✓ Given 1000 coins with a total investment of &lt;span class="nv"&gt;$1000&lt;/span&gt;  
When coin price raise up to &lt;span class="nv"&gt;$2&lt;/span&gt; 
    And holding value should be &lt;span class="nv"&gt;$2000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What are the problems with this test and report?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test code is hard to read. There are &lt;code&gt;group,&lt;/code&gt; &lt;code&gt;setUp,&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; terms that are technically specialized and make it difficult to read what the test is about. And BDD involves using simpler terms and formulations that any team member, even a person far from programming, will be able to read the test and understand what it is about.&lt;/li&gt;
&lt;li&gt;If you look at the report, we will notice the duplication of the &lt;code&gt;GIVEN&lt;/code&gt; and &lt;code&gt;WHEN&lt;/code&gt; blocks, and now it is not easy to merge the &lt;code&gt;THEN&lt;/code&gt; and &lt;code&gt;AND&lt;/code&gt; blocks so that the report looks exactly like the script itself. And an annoying &lt;code&gt;\n&lt;/code&gt; with a tab in the test description also spoils the test's code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here the first Dart package &lt;a href="https://pub.dev/packages/given_when_then_unit_test" rel="noopener noreferrer"&gt;given_when_then_unit_test&lt;/a&gt; comes to our aid. Which helps us to write test as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'1000 coins with a total investment of &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000'&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;coinAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;totalInvestment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'coin price raise up to &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;2'&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="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;PnlCalculatorResult&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PnlCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;coinAmount:&lt;/span&gt; &lt;span class="n"&gt;coinAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;totalInvestments:&lt;/span&gt; &lt;span class="n"&gt;totalInvestment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;currentPrice:&lt;/span&gt; &lt;span class="mi"&gt;2&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="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'PNL % should be 100%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nl"&gt;and:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;'PNL value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="s"&gt;'holding value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;2000'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the report will completely copy the scenario text, and the test code itself &lt;del&gt;exactly&lt;/del&gt; almost copies the script text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Given 1000 coins with a total investment of &lt;span class="nv"&gt;$1000&lt;/span&gt; 
When coin price raise up to &lt;span class="nv"&gt;$2&lt;/span&gt; 
Then PNL % should be 100%
  And PNL value should be &lt;span class="nv"&gt;$1000&lt;/span&gt;
  And holding value should be &lt;span class="nv"&gt;$2000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/Fkmgse8OMKn9C/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/Fkmgse8OMKn9C/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shouldly
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;and the test code itself &lt;del&gt;exactly&lt;/del&gt; almost copies the script text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...except for these assertion lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'PNL % should be 100%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nl"&gt;and:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;'PNL value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s"&gt;'holding value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;2000'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we will fix this now with the second Dart package &lt;a href="https://pub.dev/packages/shouldly" rel="noopener noreferrer"&gt;shouldly&lt;/a&gt;, which will allow you to write more expressively, after which the assertions will be read more naturally, like a typical English sentence.&lt;/p&gt;

&lt;p&gt;And these assertions would be written as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in this way, the test code completely copies the text of the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;'PNL % should be 100%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;and:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'PNL value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;'holding value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;2000'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  More Features
&lt;/h3&gt;

&lt;p&gt;There are several reasons why you should use &lt;code&gt;shouldly&lt;/code&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Contextual fail messages
&lt;/h4&gt;

&lt;p&gt;Let's imagine that we check for equality of two numerical values ​​and, in the case when they are not equal; we get the following report for the failure of the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Expected: &amp;lt;10&amp;gt;
  Actual: &amp;lt;100&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Who can say what those 100 and 10 are? What are these variables, and what is specifically compared there? We do not have such information. Only if we look in the logs and find a test description we could understand.&lt;/p&gt;

&lt;p&gt;But if you imagine that there are two assertions in one test, what should not be done and what I talk about in &lt;a href="https://www.youtube.com/watch?v=FWra0ORVios&amp;amp;t=1632s" rel="noopener noreferrer"&gt;this video&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'many expectations in single test'&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="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How do you know which statement is false? Well, you can again dig in the logs and find a line. Or add &lt;code&gt;reason&lt;/code&gt; to &lt;code&gt;expect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;reason:&lt;/span&gt; &lt;span class="s"&gt;'Health in the beginning should be 100'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, if the test fails, we will have a context why it happened. But the error message doesn't look natural.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Expected: &amp;lt;100&amp;gt;
  Actual: &amp;lt;10&amp;gt;
Health &lt;span class="k"&gt;in &lt;/span&gt;the beginning should be 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;shouldly&lt;/code&gt;, the same erroneous assertion would be written like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test failure message will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Expected &lt;span class="sb"&gt;`&lt;/span&gt;int&lt;span class="sb"&gt;`&lt;/span&gt;
    should be
100
    but was
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we specify the name of the variable through &lt;code&gt;.as('some alias').&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'hero health'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then we will get a more pleasant and understandable message about the reason for the test failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Expected &lt;span class="sb"&gt;`&lt;/span&gt;hero health&lt;span class="sb"&gt;`&lt;/span&gt;
    should be
100
    but was
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, a typing in Dart doesn't work like it does in .NET. In .NET, we can get information about a variable and its properties, and we wouldn't have to use &lt;code&gt;.as('some alias').&lt;/code&gt;, for example, as shown &lt;a href="https://docs.shouldly.io/documentation/equality/shouldbe" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Who knows, maybe this feature will be in the future releases of Dart.&lt;/p&gt;

&lt;h4&gt;
  
  
  Confusion actual with expected
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;expect&lt;/code&gt; method takes two parameters, one is &lt;code&gt;matcher&lt;/code&gt; (or &lt;code&gt;expected&lt;/code&gt;) and the other is &lt;code&gt;actual&lt;/code&gt;. Could you tell me, which one is the first parameter of the &lt;code&gt;expect&lt;/code&gt; function, and which one is the second one?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both recorded assertions will pass.&lt;/p&gt;

&lt;p&gt;Let's now try to specify the &lt;code&gt;isZero&lt;/code&gt; matcher.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isZero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isZero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before running the test, everything seemed to be okay - there were no compilation errors.&lt;/p&gt;

&lt;p&gt;BUT! The second statement will fail and will produce a bizarre error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Expected: &amp;lt;0&amp;gt;
  Actual: a value equal to &amp;lt;0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/l2QE1bH4wvCE8CcTK/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l2QE1bH4wvCE8CcTK/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The assertions heap
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;shouldly&lt;/code&gt; does not lump everything together, all expect helpers or matchers.&lt;/p&gt;

&lt;p&gt;For example, you can't test a numeric type against an empty string, as you can with &lt;code&gt;expect&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;shouldy&lt;/code&gt; everything is relative to the type of the result we need to check.&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%2F3onx1b8j65y8i8yqcaby.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%2F3onx1b8j65y8i8yqcaby.png" alt="Shouldly of Number"&gt;&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%2Ferw7e2u998x0ab7v3v6w.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%2Ferw7e2u998x0ab7v3v6w.png" alt="Shouldly of String"&gt;&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%2Fv7g60n0hg6hmn5yl8t4o.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%2Fv7g60n0hg6hmn5yl8t4o.png" alt="Shouldly of List"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ℹ️ More features here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/shouldly#custom-matchers" rel="noopener noreferrer"&gt;Custom matchers&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/shouldly#conjunctions" rel="noopener noreferrer"&gt;Conjunctions&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/shouldly#satisfyallconditions" rel="noopener noreferrer"&gt;SatisfyAllConditions&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;and others can be found on the page &lt;a href="https://pub.dev/packages/shouldly" rel="noopener noreferrer"&gt;of the library itself on pub.dev&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test Cases
&lt;/h2&gt;

&lt;p&gt;Ideally, you need to test many cases (&lt;strong&gt;test cases&lt;/strong&gt;). And at the writing each case separately, there will be a problem of duplication of the code. The &lt;code&gt;testCases&lt;/code&gt; methods come to the rescue, which allows you to &lt;em&gt;parameterize&lt;/em&gt; the test.&lt;/p&gt;

&lt;p&gt;This method has two parameters, the first is an array of &lt;code&gt;TestCase&lt;/code&gt; objects that specifies the input and output values, and the second parameter is a function called on each test case.&lt;/p&gt;

&lt;p&gt;In our example with the PnL calculator, we will test two more test cases: one for loss and the other for the case when there is no change in the coin price.&lt;/p&gt;

&lt;p&gt;Here's what the test with cases would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'1000 coins and with a total investment of &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="s"&gt;1000'&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;coinAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;totalInvestment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;testCases4&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;([&lt;/span&gt;
    &lt;span class="n"&gt;TestCase4&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;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;TestCase4&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;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;TestCase4&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// ...more Test Cases&lt;/span&gt;
  &lt;span class="p"&gt;],&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'the coin price became &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="si"&gt;${testCase.arg1}&lt;/span&gt;&lt;span class="s"&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="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;PnlCalculatorResult&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PnlCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;coinAmount:&lt;/span&gt; &lt;span class="n"&gt;coinAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;totalInvestments:&lt;/span&gt; &lt;span class="n"&gt;totalInvestment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;currentPrice:&lt;/span&gt; &lt;span class="n"&gt;testCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arg1&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="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'PNL % should be &lt;/span&gt;&lt;span class="si"&gt;${testCase.arg2}&lt;/span&gt;&lt;span class="s"&gt;%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;and:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;'PNL value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="si"&gt;${testCase.arg3}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arg3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="s"&gt;'holding value should be &lt;/span&gt;&lt;span class="err"&gt;\$&lt;/span&gt;&lt;span class="si"&gt;${testCase.arg4}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;holdingValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arg4&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="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/XreQmk7ETCak0/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/XreQmk7ETCak0/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;So with two packages &lt;a href="https://pub.dev/packages/given_when_then_unit_test" rel="noopener noreferrer"&gt;given_when_then_unit_test&lt;/a&gt; and &lt;a href="https://pub.dev/packages/shouldly" rel="noopener noreferrer"&gt;shouldly&lt;/a&gt; we can improve:&lt;/p&gt;

&lt;p&gt;1) readability of test code,&lt;br&gt;
2) test reports,&lt;br&gt;
3) and get a more detailed reason for the error, when the test fails.&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%2F3em3od6xttm28ttmxfk7.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%2F3em3od6xttm28ttmxfk7.png" alt="given_when_then_unit_test with shouldly"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's useful to note,&lt;/p&gt;

&lt;p&gt;The above BDD style technique does not always need to be used in unit testing. But where it is possible, where you can describe the &lt;em&gt;behavior&lt;/em&gt; of a unit, you can safely take and describe "live documentation".&lt;br&gt;
Each of these libraries can be used separately, but together they give a stunning result.&lt;/p&gt;

&lt;p&gt;Good luck with your beautiful writing! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Contribution
&lt;/h2&gt;

&lt;p&gt;Feel free to contribute these packages 🙏&lt;/p&gt;

</description>
      <category>dart</category>
      <category>flutter</category>
      <category>tdd</category>
      <category>bdd</category>
    </item>
    <item>
      <title>Ugly API</title>
      <dc:creator>Andrew Piterov</dc:creator>
      <pubDate>Tue, 13 Apr 2021 07:56:21 +0000</pubDate>
      <link>https://dev.to/andrewpiterov/ugly-api-1o25</link>
      <guid>https://dev.to/andrewpiterov/ugly-api-1o25</guid>
      <description>&lt;h1&gt;
  
  
  Ugly API
&lt;/h1&gt;

&lt;p&gt;In this article, I’d like to talk about the problems I faced while integrating an API for the HTTP protocol and share my experience in solving them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table Of Contents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;REST vs Non REST architecture&lt;/li&gt;
&lt;li&gt;Ignoring Header Accept: application/json&lt;/li&gt;
&lt;li&gt;Mixing JSON keys case types&lt;/li&gt;
&lt;li&gt;Different response to the same request&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;When developing a frontend for Mobile/Web apps, you often come across the fact that the backend has not been implemented yet. So, you have to wait for the developer on the backend when he provides the necessary requests persistently drawing his attention to yourself. And another situation when the necessary http requests have already existed, but they are very poorly and crookedly implemented is far from being unusual.&lt;/p&gt;

&lt;p&gt;Maybe, I wouldn’t have written this article. But the fact that all the examples of poor API implementation I’m giving below came across to me in the same project and at the same time seemed very impressive to me!&lt;/p&gt;

&lt;p&gt;In this project, I am developing a mobile app in Flutter using the Retrofit package, which helps me save time and reduce code and I have to write myself generating significant code automatically. And I use Insomnia for the initial verification of requests before implementing them in the code as well.&lt;/p&gt;

&lt;p&gt;Before I show the issues that I faced, I would like to mention that before I became a mobile developer I have been working as a Full-Stack developer for more than 5 years. And I understand how important it is to implement beautiful API for many frontend clients, with which it is easy and pleasant to integrate and safe, in case of future changes in the API.&lt;/p&gt;

&lt;p&gt;Video version available on YouTube on Russian&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=oj-i1IBejcI"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nLagNr6m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://img.youtube.com/vi/oj-i1IBejcI/0.jpg" alt="Ugly API" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, let’s start.&lt;/p&gt;

&lt;h2&gt;
  
  
  REST vs Non REST architecture
&lt;/h2&gt;

&lt;p&gt;The fact that the API architecture is not implemented in the RESTful style was the first disappointment. To be honest, I don’t remember when I had to face such a situation.&lt;/p&gt;

&lt;p&gt;REST stands for &lt;strong&gt;RE&lt;/strong&gt;presentational &lt;strong&gt;S&lt;/strong&gt;tate &lt;strong&gt;T&lt;/strong&gt;ransfer. RESTful is a sort of API architecture implementation that makes use of the HTTP protocol in the best way possible. With REST, we need to think about the app in terms of resources and to determine which resources we want to expose to the outside world (for example, tasks, customers, etc.). Here we use the verbs defined by the HTTP protocol to perform CRUD operations on these resources, such as GET, POST, PUT, DELETE, etc.&lt;/p&gt;

&lt;p&gt;Here is a RESTful API example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NYViVdu---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51yaljo6fgoabi394dvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NYViVdu---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51yaljo6fgoabi394dvx.png" alt="2_1_RESTfull_example" width="512" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My project’s API architecture that is non-RESTful architecture looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bwFYFVrg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9tw1qcu4v3wpb16rzge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bwFYFVrg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9tw1qcu4v3wpb16rzge.png" alt="2_2_non-RESTfull_example" width="477" height="512"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You can see that all requests are presented in the same type — these are POST requests. And each request must contain a type parameter that defines the operation. Apparently, on the server, in this single endpoint, there are some if-else or switch-statements for checking this parameter.&lt;/p&gt;

&lt;p&gt;Naturally, I prefer RESTful, but since the other implementation works properly and it is possible to more or less configure requests with Retrofit on the client, I accepted this fact and continued to integrate with the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ignoring Header Accept: application/json
&lt;/h2&gt;

&lt;p&gt;Usually, I first check a request to API in Insomnia and then implement them in my code.&lt;/p&gt;

&lt;p&gt;After I made a request in Insomnia, I saw a nice json in the Preview tab and thought that a json object was coming to me. I formalized all this in my code; Retrofit automatically converted response to the request to a Dart class for me, and everything worked great.&lt;/p&gt;

&lt;p&gt;But the next day, my app stopped working due to an error related to the request to the server. The error text was: “An error when converting the line to an object occurs”.&lt;/p&gt;

&lt;p&gt;I went back to Insomnia again and checked the request. I saw the same json as before in the Preview tab. And only after checking the Header of the request, I found that the Content-Type has changed, and its value has already been text/html, charset-utf-8, although the Preview shows me json.&lt;/p&gt;

&lt;p&gt;Thus, I determined that the response type from the server changed from application/json to text/html due to which Retrofit can no longer convert the response from the server of the line type automatically to a Dart object.&lt;/p&gt;

&lt;p&gt;I decided to try using Accept Header in a request that will tell the server something that “I’m a client expecting a json response from you”. But it didn’t work because the server doesn’t consider this header.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJtBty8g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/41tualv53uz5xzdo0a9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJtBty8g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/41tualv53uz5xzdo0a9e.png" alt="3_1_header_accept" width="512" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And again, I had to add even more code to work around this server response type issue.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Added a new version of the request to Retrofit where I expect a response as “String” type in the second version&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j67EfIrf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09wqakvne9muoc2szxvb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j67EfIrf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09wqakvne9muoc2szxvb.png" alt="3_2_second_sign_in" width="512" height="426"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Then I started initiating a new version of the query that returns a String and added a conversion String to object. Meanwhile, Retrofit could do this conversion itself in the code it generated. And now, in every place where we make requests to the server, we must add this conversion ourselves to receive responses from it:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ypQYQIF3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/se45ohailwd2su5qvxvy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ypQYQIF3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/se45ohailwd2su5qvxvy.png" alt="3_3_second_sign_in_use" width="880" height="609"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As a result, even more code lines were added, which is not encouraging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mixing JSON keys case types
&lt;/h2&gt;

&lt;p&gt;There are several types of formatting field names in json:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0nPIHQz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7nvsaysvqnr7wv1hmpa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0nPIHQz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7nvsaysvqnr7wv1hmpa.png" alt="4_1_json_keys_case_types" width="880" height="383"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In an ideal scenario, you need to choose one option you like and comply with it during the whole project and in all requests. But in my project, the backend developer decided to mix several types:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dEZ0KzVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4flzb3oe7y231can4uu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dEZ0KzVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4flzb3oe7y231can4uu.png" alt="4_2_json_mixed" width="880" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In an ideal scenario, the camelCase style is used for naming class fields and methods in Dart. And if json comes from the server with fields in camelCase style, then Retrofit will automatically, without any effort, correctly match the class and json fields. But in this situation, I have to specify additional JsonKey annotations, which are as snake_case in one case, and as UPPER_CASE_SNAKE_CASE in the other one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f9lc0WZr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8km500j0mwxcc2kmsgg8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f9lc0WZr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8km500j0mwxcc2kmsgg8.png" alt="4_3_json_mixing" width="880" height="449"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As a result, there is no uniformity; if you make a mistake in the case type, you can lose the meaning since the fields will not match. I got even angrier at the API, but the integration with the API could still be continued with more effort and even more code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different response to the same request
&lt;/h2&gt;

&lt;p&gt;Here I almost got heart attack… When I tried to log into the app as a different user, my app broke again. I got the following error: “Could not convert String to Int”. This was due to the fact that my class describing the response from the server became incorrect. The types described in the class don’t correspond to the types of fields available in the json response. I opened Insomnia again and ran the same login request for two different users. And I found that the numbers come as Strings in response in one case, and they come as numbers in the other one. 🤯 You can see that in Insomnia, the lines are highlighted in yellow, and the numbers are in purple:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QGP_r3Ns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cblvrxuawpxbidui2cx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QGP_r3Ns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cblvrxuawpxbidui2cx4.png" alt="5_diff_responce" width="880" height="444"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;How can it be that the same json arrives for the same request, but with different types of values?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O9UXrCNY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36f0q81rk3g9iizjqq3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O9UXrCNY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36f0q81rk3g9iizjqq3q.png" alt="6_Homer_boom" width="448" height="486"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I know the server was written in PHP. Folks, who encode in PHP, could you write in the comments how is this possible?&lt;/p&gt;

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

&lt;p&gt;Currently, I am experiencing the opposite feelings. On the one part, I’m upset that I have to integrate such an ugly server, and on the other part, I’m already looking forward to the next case that will show how else you can disfigure the API.&lt;/p&gt;

&lt;p&gt;I’d like to know about your experience in integrating with the API, and what problems you faced.&lt;/p&gt;

&lt;p&gt;Thank you in advance. Happy coding! 👨🏻‍💻&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>php</category>
      <category>api</category>
      <category>http</category>
    </item>
  </channel>
</rss>
