<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ TDD (Test-driven development) - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ TDD (Test-driven development) - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 11 Jun 2026 23:15:02 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/tdd/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use pytest: A Simple Guide to Testing in Python ]]>
                </title>
                <description>
                    <![CDATA[ With the recent advancements in AI, tools like ChatGPT have made the development process faster and more accessible. Developers can now write code and build web apps with some well-articulated prompts and careful code reviews. While this brings an in... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-pytest-a-guide-to-testing-in-python/</link>
                <guid isPermaLink="false">686d82b56332ba136ecc139e</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pytest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ guide ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Olowo Jude ]]>
                </dc:creator>
                <pubDate>Tue, 08 Jul 2025 20:42:29 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752007334998/e196493e-f3e0-4e63-b6eb-ce66c5481d9c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>With the recent advancements in AI, tools like ChatGPT have made the development process faster and more accessible. Developers can now write code and build web apps with some well-articulated prompts and careful code reviews.</p>
<p>While this brings an increase in productivity, there's a growing downside. AI-generated code is prone to errors, unexpected bugs, or poor integration with the rest of your code.</p>
<p>Because of these risks, it’s more important than ever to establish robust testing practices to make sure your code is high quality and properly functioning. Various testing tools are available to help solve these challenges, and pytest stands out in the Python ecosystem for its simplicity, flexibility, and powerful features.</p>
<p>In this article, we'll explore the following topics:</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-use-pytest">Why Use pytest?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-write-your-first-tests-with-pytest">How to Write Your First Tests with pytest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-run-pytest-tests">How to Run pytest Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-interpret-pytest-results">How to Interpret pytest Results</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-exceptions-in-pytest">How to Handle Exceptions in pytest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advanced-pytest-features">Advanced pytest Features</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-pytest-markers">1. pytest Markers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-pytest-fixtures">2. pytest Fixtures</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-parametrization">3. Parametrization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-pytest-plugins">4. pytest Plugins</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>By the end of this article, you will have a comprehensive knowledge of pytest and be able to use it in your Python development process.</p>
<h2 id="heading-pre-requisites"><strong>Pre-requisites</strong></h2>
<ul>
<li><p>Must have Python installed</p>
</li>
<li><p>An understanding of the Python programming language</p>
</li>
</ul>
<h2 id="heading-why-use-pytest">Why Use pytest?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751221734601/f5d6093a-37d2-4d49-85f2-c1a41a98ab67.png" alt="An image of pytest logo." class="image--center mx-auto" width="742" height="677" loading="lazy"></p>
<p>pytest is a popular testing framework for Python that makes it easy to write and run tests. Unlike unittest and other Python testing frameworks, pytest’s simple syntax allows developers to write tests directly as functions or within classes. This lets you write clean, readable code without complexities.</p>
<p>pytest also supports popular Python frameworks like Flask, Django, and more. Combined with other rich features, pytest equips you with the tools you need to ship reliable software in today’s AI-driven era.</p>
<p>Key features of pytest that make it a preferred testing tool include:</p>
<ul>
<li><p><strong>Flexibility:</strong> it provides flexibility in test structure by supporting tests for functions, classes, and modules.</p>
</li>
<li><p><strong>Detailed test output:</strong> it provides a detailed and readable test output, making it easy to understand test failures and errors.</p>
</li>
<li><p><strong>Automatic test discovery:</strong> it automatically discovers tests by looking for files that start with "<code>test_</code>" or end with "<code>_test.py</code>". This eliminates the need for manually specifying test files**.**</p>
</li>
<li><p><strong>Parameterization:</strong> it supports parameterized tests, which allow you to run a single test function with multiple sets of inputs.</p>
</li>
<li><p><strong>Fixtures:</strong> it fixtures provide <code>setup</code> and <code>tearDown</code> methods that help prevent code repetition. This enables you to set up baseline conditions for your tests and also delete them after each test.</p>
</li>
<li><p><strong>Plugins and extensions:</strong> it has a rich ecosystem of plugins and extensions that add extra functionalities, such as detailed tests reporting, and integration with other tools and Python frameworks like Django and Flask.</p>
</li>
<li><p><strong>Compatibility:</strong> it is compatible with other testing frameworks like <code>unittest</code> , allowing you to migrate tests from different testing frameworks and run them seamlessly on it.</p>
</li>
</ul>
<h2 id="heading-how-to-write-your-first-tests-with-pytest">How to Write Your First Tests with pytest</h2>
<p>This section will guide you through writing your first set of tests using the pytest framework.</p>
<p>pytest is a Python package, and you’ll need to install it before using it. You can do that with the following command:</p>
<pre><code class="lang-python">pip install pytest
</code></pre>
<p><strong>NOTE:</strong> Following Python's best practices, it’s recommended you install pytest within a virtual environment. <a target="_blank" href="https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/">Here's a guide</a> to help you set it up.</p>
<p>Next, create a Python file where you will write your tests and import pytest into it using:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pytest
</code></pre>
<p>pytest has 2 basic methods of writing tests, which include:</p>
<ul>
<li><p><strong>The function-based method:</strong> This method is straightforward for writing tests because you write the tests in individual functions.</p>
<p>  <strong>Note:</strong> Each function name must be prefixed with the word <code>test_</code> for pytest to discover and run these tests automatically.</p>
<p>  Here’s an example of a function-based test:</p>
<pre><code class="lang-python">  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_addition</span>():</span>
      <span class="hljs-keyword">assert</span> <span class="hljs-number">1</span> + <span class="hljs-number">1</span> == <span class="hljs-number">2</span>
</code></pre>
<p>  <strong>Note:</strong> In the code above, the <code>assert</code> statement used here in pytest is Python’s built-in “<code>assert</code>”. It’s more convenient and doesn’t require the specific methods like <code>assertEqual</code> and <code>assertTrue</code> which are common with unittest. Another advantage of using the <code>assert</code> statement is that it provides more detailed error messages when an assertion fails.</p>
</li>
<li><p><strong>Class-based method:</strong> This method is similar to the way of writing tests in <code>unittest</code>, except that your test class does not inherit any methods. An example is shown below:</p>
<pre><code class="lang-python">  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestMathOperations</span>:</span>
      <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_addition</span>(<span class="hljs-params">self</span>):</span>
          <span class="hljs-keyword">assert</span> <span class="hljs-number">1</span> + <span class="hljs-number">1</span> == <span class="hljs-number">2</span>
</code></pre>
<p>  This method of writing tests in pytest is useful when you want to group related tests together.</p>
</li>
</ul>
<h2 id="heading-how-to-run-pytest-tests">How to Run pytest Tests</h2>
<p>Running pytest differs slightly from the normal convention of running regular Python scripts.</p>
<p>The general method of running pytest tests is by running the <code>pytest</code> command in your terminal. pytest will automatically look for and run all files of the form <code>test_*.py</code> or <code>*_test.py</code> in the current directory and subdirectories. But while this may be a great way to run tests, pytest offers more flexibility beyond this general method of running tests.</p>
<p>Depending on preferences, you may want to run your test files based on the following:</p>
<ol>
<li><p><strong>To run a specific test file</strong>: To run tests in a specific file, use the <code>pytest</code> command followed by the file name. For example: <code>pytest test_example.py</code>.</p>
</li>
<li><p><strong>To run tests in a directory:</strong> Let’s say you have a directory named Tests that contains some test files. To run all the tests in that directory, use the <code>pytest</code> command followed by the directory and a forward slash. For example: <code>pytest Tests/</code>.</p>
</li>
<li><p><strong>To run tests using specific keywords:</strong> To run tests based on a certain keyword, use the command <code>pytest -k "keyword"</code>. Pytest will automatically look for and run function names, class names, or file names matching that keyword in the current directory and subdirectories. But to run tests matching a certain keyword in a specific file, you’d have to specify the file name after the <code>pytest</code> command. For example: <code>pytest test_example.py -k "keyword"</code>.</p>
</li>
<li><p><strong>Run a specific test within a test file:</strong> To run only a specific test inside a test file, use the command <code>pytest test_example.py::test_addition</code>. This will run only the <code>test_addition</code> test function within the <code>test_example.py</code> module.</p>
</li>
<li><p><strong>To run all test methods in a specific class</strong>: To run all the tests within a specific class, use <code>pytest test_example.py::TestClass</code>. This command would run all the test methods inside the <code>TestClass</code> class in the <code>test_example.py</code> module.</p>
</li>
<li><p><strong>To run a specific test method inside a specific class:</strong> To run a specific test inside a specific class, use <code>pytest test_example.py::TestClass::test_addition</code>. This command would run the specific <code>test_addition</code> method within the <code>TestClass</code> class in the <code>test_example.py</code> module.</p>
</li>
</ol>
<h2 id="heading-how-to-interpret-pytest-results">How to Interpret pytest Results</h2>
<p>One major advantage pytest has over other Python testing frameworks is the rich output it provides, which gives very detailed information about the status of your tests.</p>
<p>Let’s use a basic test to understand how to interpret pytest’s output:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pytest

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_addition</span>():</span>
    <span class="hljs-keyword">assert</span> <span class="hljs-number">1</span> + <span class="hljs-number">1</span> == <span class="hljs-number">3</span>
</code></pre>
<p>Run this test, and we get an output similar to the one below:</p>
<pre><code class="lang-python">============================== test session starts ====================================
platform win32 -- Python <span class="hljs-number">3.10</span><span class="hljs-number">.5</span>, pytest<span class="hljs-number">-8.4</span><span class="hljs-number">.1</span>, pluggy<span class="hljs-number">-1.6</span><span class="hljs-number">.0</span>
rootdir: C:\\Users\\hp\\Desktop\\Pytest
collected <span class="hljs-number">1</span> items

                                                                                  [ <span class="hljs-number">50</span>%]
test_example.py F                                                                 [<span class="hljs-number">100</span>%]

===================================== FAILURES =========================================
____________________________________test_addition ______________________________________

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_addition</span>():</span>
&gt;       <span class="hljs-keyword">assert</span> <span class="hljs-number">1</span> + <span class="hljs-number">1</span> == <span class="hljs-number">3</span>
E       <span class="hljs-keyword">assert</span> (<span class="hljs-number">1</span> + <span class="hljs-number">1</span>) == <span class="hljs-number">3</span>

test_example.py:<span class="hljs-number">4</span>: AssertionError
============================== short test summary info =================================
FAILED test_example.py::test_addition - <span class="hljs-keyword">assert</span> (<span class="hljs-number">1</span> + <span class="hljs-number">1</span>) == <span class="hljs-number">3</span>
========================= <span class="hljs-number">1</span> failed, <span class="hljs-number">1</span> passed <span class="hljs-keyword">in</span> <span class="hljs-number">0.13</span>s ==================================
</code></pre>
<p>The above output is divided into several sections. Here’s a breakdown of what each section means:</p>
<ol>
<li><p>Test session information:</p>
<pre><code class="lang-python"> =============================== test session starts ===============================
 platform win32 -- Python <span class="hljs-number">3.10</span><span class="hljs-number">.5</span>, pytest<span class="hljs-number">-8.4</span><span class="hljs-number">.1</span>, pluggy<span class="hljs-number">-1.6</span><span class="hljs-number">.0</span>
 rootdir: C:\\Users\\hp\\Desktop\\TDD pytest
 collected <span class="hljs-number">1</span> item
</code></pre>
<ul>
<li><p>This section displays a summary of the test environment. It begins with a line marker that indicates the beginning of the test session.</p>
</li>
<li><p>Below the marker, pytest displays information about the operating system, along with the installed versions of Python, pytest and pluggy. (Pluggy is a pytest dependency used to manage plugins.)</p>
</li>
<li><p>The next line indicates the root directory where the test is being run.</p>
</li>
<li><p>The last line in this section displays the number of tests found in this directory.</p>
</li>
</ul>
</li>
<li><p>Test status:</p>
<pre><code class="lang-python"> test_example.py F                                                              [<span class="hljs-number">100</span>%]

 ================================== FAILURES =========================================
 ________________________________ test_addition ______________________________________

     <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_addition</span>():</span>
 &gt;       <span class="hljs-keyword">assert</span> <span class="hljs-number">1</span> + <span class="hljs-number">1</span> == <span class="hljs-number">3</span>
 E       <span class="hljs-keyword">assert</span> (<span class="hljs-number">1</span> + <span class="hljs-number">1</span>) == <span class="hljs-number">3</span>

 test_example.py:<span class="hljs-number">4</span>: AssertionError
</code></pre>
<ul>
<li><p>This section displays information about the status of our tests</p>
</li>
<li><p>The first line in this section specifies the test file which is being run, followed by the status (F in this case, which indicates a test failure).</p>
</li>
<li><p>The next set of lines gives specific information about the failed tests. This includes the function where the failure occurred (<code>test_addition</code>), and the exact line of code responsible for the error.</p>
</li>
<li><p>The last line gives a concise summary of this section. It indicates that the error occurred in <code>test_example.py</code> on line <code>4</code> and it was an <code>AssertionError</code>.</p>
</li>
</ul>
</li>
<li><p>Test summary:</p>
<pre><code class="lang-python"> ============================= short test summary info =============================
 FAILED test_example.py::test_addition - <span class="hljs-keyword">assert</span> (<span class="hljs-number">1</span> + <span class="hljs-number">1</span>) == <span class="hljs-number">3</span>
 ================================ <span class="hljs-number">1</span> failed <span class="hljs-keyword">in</span> <span class="hljs-number">0.13</span>s ================================
</code></pre>
<ul>
<li><p>This section provides an overall summary of the test.</p>
</li>
<li><p>It indicates that the failed test occurred in <code>test_example.py</code> file in the <code>test_addition</code> function because of an incorrect assertion <code>(1 + 1) == 3</code> which isn’t true.</p>
</li>
</ul>
</li>
</ol>
<p>Edit the code with the correct assertion <code>assert(1 + 1) == 2</code> and rerun the code. This time, the code passes with a different output.</p>
<pre><code class="lang-python">=============================== test session starts ==================================
platform win32 -- Python <span class="hljs-number">3.10</span><span class="hljs-number">.5</span>, pytest<span class="hljs-number">-8.3</span><span class="hljs-number">.2</span>, pluggy<span class="hljs-number">-1.5</span><span class="hljs-number">.0</span>
rootdir: C:\\Users\\hp\\Desktop\\TDD pytest
collected <span class="hljs-number">1</span> items

test_example.py .                                                               [<span class="hljs-number">100</span>%]

=============================== <span class="hljs-number">1</span> passed <span class="hljs-keyword">in</span> <span class="hljs-number">0.01</span>s =================================
</code></pre>
<h3 id="heading-how-to-handle-exceptions-in-pytest">How to Handle Exceptions in pytest</h3>
<p>Exceptions are unexpected errors that occur while running our tests, and they prevent our code from performing as expected. As a result, pytest offers several built-in mechanisms for handling these exceptions (but we’ll just cover one of them in this article).</p>
<p><code>pytest.raises</code> <strong>Context Manager</strong> is a tool that checks if your code raises specific exceptions. If the specified exception is raised, that test passes, confirming that the expected error occurred. But if the specified exception is not raised, that test fails.</p>
<p><strong>Usage Examples of</strong> <code>pytest.raises</code></p>
<ol>
<li><p><strong>Checking for</strong> <code>ValueError</code>: In Python, a <code>ValueError</code> is raised when a function receives an argument with an incorrect value. In the example below, we can verify that a <code>ValueError</code> is raised when attempting to calculate the square root of a negative number.</p>
<pre><code class="lang-python"> <span class="hljs-keyword">import</span> pytest
 <span class="hljs-keyword">import</span> math

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_square_root</span>(<span class="hljs-params">value</span>):</span>
     <span class="hljs-keyword">if</span> value &lt; <span class="hljs-number">0</span>:
         <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Cannot calculate the square root of a negative number"</span>)
     <span class="hljs-keyword">return</span> math.sqrt(value)

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_calculate_square_root</span>():</span>
     <span class="hljs-keyword">with</span> pytest.raises(ValueError):
         calculate_square_root(<span class="hljs-number">-1</span>)
</code></pre>
</li>
<li><p><strong>Checking for</strong> <code>ZeroDivisionError</code>: Dividing a number by zero raises a <code>ZeroDivisionError</code>. In this example, we check that this error is raised when dividing a number by zero.</p>
<pre><code class="lang-jsx"> <span class="hljs-keyword">import</span> pytest

 def divide_numbers(numerator, denominator):
     <span class="hljs-keyword">return</span> numerator / denominator

 def test_divide_numbers():
     <span class="hljs-keyword">with</span> pytest.raises(ZeroDivisionError):
         divide_numbers(<span class="hljs-number">10</span>, <span class="hljs-number">0</span>)
</code></pre>
</li>
<li><p><strong>Checking for</strong> <code>TypeError</code>: A <code>TypeError</code> is raised when an operation is applied to an object of an inappropriate type. Here, we check that this error is raised when adding incompatible data types, such as a string and an integer given in the example.</p>
<pre><code class="lang-jsx"> <span class="hljs-keyword">import</span> pytest

 def add_numbers(a, b):
     <span class="hljs-keyword">return</span> a + b

 def test_add_numbers():
     <span class="hljs-keyword">with</span> pytest.raises(<span class="hljs-built_in">TypeError</span>):
         add_numbers(<span class="hljs-string">"10"</span>, <span class="hljs-number">5</span>)
</code></pre>
</li>
<li><p><strong>Checking for</strong> <code>KeyError</code>: A <code>KeyError</code> is raised when we try to access a dictionary key that doesn’t exist. We can verify and handle this error using the following code:</p>
<pre><code class="lang-python"> <span class="hljs-keyword">import</span> pytest

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_value</span>(<span class="hljs-params">dictionary, key</span>):</span>
     <span class="hljs-keyword">return</span> dictionary[key]

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_get_value</span>():</span>
     <span class="hljs-keyword">with</span> pytest.raises(KeyError):
         get_value({<span class="hljs-string">"name"</span>: <span class="hljs-string">"Alice"</span>}, <span class="hljs-string">"age"</span>)
</code></pre>
</li>
</ol>
<h2 id="heading-advanced-pytest-features">Advanced pytest Features</h2>
<p>As a robust testing framework, pytest offers some advanced features that help you manage complex test scenarios. In this section, we will explore some of these advanced features at a beginner-friendly level and demonstrate how you can start applying them in your tests.</p>
<h3 id="heading-1-pytest-markers">1. pytest Markers</h3>
<p>When working with a large codebase, sometimes running every single test can be time-consuming. This is where pytest markers come in handy.</p>
<p>A marker is just like a label that you can attach to a test function to categorise it. Once a test is labelled, you can instruct pytest to run only tests with certain markers. For example, you may label some tests as "slow" if they take longer to execute and run them separately from the faster ones.</p>
<p>One advantage to using Markers is that it allows you to run specific tests based on categories or specific parameters, and also skip tests if certain conditions aren’t met.</p>
<p>pytest comes along with some built-in markers that can be quite useful:</p>
<ol>
<li><p><code>@pytest.mark.skip</code>: This marker allows you to skip a test unconditionally, and can be useful when you know a test will fail due to an external issue or incomplete code.</p>
<p> <strong>Example:</strong></p>
<pre><code class="lang-python"><span class="hljs-meta"> @pytest.mark.skip(reason="Feature not yet implemented")</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_feature</span>():</span>
     <span class="hljs-keyword">pass</span>
</code></pre>
</li>
<li><p><code>@pytest.mark.skipif</code>: This marker allows you to skip a test conditionally if certain conditions are met.</p>
<p> <strong>Example:</strong></p>
<pre><code class="lang-python"> <span class="hljs-keyword">import</span> sys

<span class="hljs-meta"> @pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")</span>
 <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestClass</span>:</span>
     <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_function</span>(<span class="hljs-params">self</span>):</span>
         <span class="hljs-string">"This test will not run under 'win32' platform"</span>
</code></pre>
</li>
<li><p><code>@pytest.mark.xfail</code>: This marker is attached to tests that are expected to fail, probably due to a bug or incomplete feature. So when pytest runs such tests, it won’t count it as a failure.</p>
<p> <strong>Example:</strong></p>
<pre><code class="lang-python"><span class="hljs-meta"> @pytest.mark.xfail(reason="division by zero not handled yet")</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_divide_by_zero</span>():</span>
     <span class="hljs-keyword">assert</span> divide(<span class="hljs-number">10</span>, <span class="hljs-number">0</span>) == <span class="hljs-number">0</span>
</code></pre>
<p> <strong>Note:</strong> Detailed information about skipped/failed tests is not shown by default to avoid cluttering the output.</p>
</li>
</ol>
<p>While pytest comes along with some built-in markers, you can also create your own custom marker (but we won’t cover that in this tutorial). Kindly refer to the documentation for more information on <a target="_blank" href="https://docs.pytest.org/en/stable/example/markers.html">working with custom markers</a></p>
<h3 id="heading-2-pytest-fixtures">2. pytest Fixtures</h3>
<p>In pytest, fixtures allow you to create reusable default data that can be shared across multiple tests. By using fixtures, you can reduce code repetition, making your tests cleaner and more maintainable.</p>
<p>In pytest, fixtures are defined with the <code>@pytest.fixture</code> decorator as shown in the example below:</p>
<p>Let’s say we have several tests that rely on a list of user data. Instead of repeating the same data in each test, we can create a fixture to hold this data, and the fixture is passed across the tests that need it.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pytest

<span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_data</span>():</span>
    <span class="hljs-keyword">return</span> [
        {<span class="hljs-string">"name"</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">30</span>},
        {<span class="hljs-string">"name"</span>: <span class="hljs-string">"Bob"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">25</span>},
        {<span class="hljs-string">"name"</span>: <span class="hljs-string">"Charlie"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">35</span>}
    ]

<span class="hljs-comment"># Test function to check for a specific user by name and age</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_user_exists</span>(<span class="hljs-params">user_data</span>):</span>
    user = {<span class="hljs-string">"name"</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">30</span>}

    <span class="hljs-comment"># Check if the target user is in the list</span>
    <span class="hljs-keyword">assert</span> user <span class="hljs-keyword">in</span> user_data

<span class="hljs-comment"># Test average age of users</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_average_age</span>(<span class="hljs-params">user_data</span>):</span>
    ages = [user[<span class="hljs-string">"age"</span>] <span class="hljs-keyword">for</span> user <span class="hljs-keyword">in</span> user_data]
    avg_age = sum(ages) / len(ages)
    <span class="hljs-keyword">assert</span> avg_age == <span class="hljs-number">30</span>
</code></pre>
<p><strong>Note:</strong> The <code>@pytest.fixture</code> decorator in the code above marks the <code>user_data</code> function as a fixture in pytest. This fixture provides reusable data that can be shared across multiple test functions, allowing them to share the same setup without repeating code.</p>
<h3 id="heading-3-parametrization">3. Parametrization</h3>
<p>Parametrization is a pytest feature that allows you to run a test function with different sets of data at once.</p>
<p>For example: Let’s say you have a function that calculates the square of a number. To provide enough coverage while testing, you would want to test the function with zero, positive, and negative numbers.</p>
<p>Instead of writing separate test functions for each scenario, you can use parametrization to run a test function with different sets of data at once. This approach is more concise, and reduces code duplication.</p>
<p>To use parametrization in pytest, we use the <code>@pytest.mark.parametrize</code> decorator as shown in the example below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pytest

<span class="hljs-comment"># Function to calculate the square of a number</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">square_numbers</span>(<span class="hljs-params">num</span>):</span>
    <span class="hljs-keyword">return</span> num * num

<span class="hljs-comment">#Parametrize decorator to test the square function with different inputs</span>
<span class="hljs-meta">@pytest.mark.parametrize("input_value, expected_output", [</span>
    (<span class="hljs-number">2</span>, <span class="hljs-number">4</span>),     
    (<span class="hljs-number">-3</span>, <span class="hljs-number">9</span>),    
    (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)    
])

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_square</span>(<span class="hljs-params">input_value, expected_output</span>):</span>
    <span class="hljs-keyword">assert</span> square_numbers(input_value) == expected_output
</code></pre>
<p>In the example above, the different input values and expected values are listed in the <code>@pytest.mark.parametrize</code> decorator. We’re testing the <code>square_numbers()</code> function with three different input values: <code>2</code>, <code>-3</code>, and <code>0</code>.</p>
<p>For each value, pytest calls the <code>test_square()</code> function and compares the result of <code>square_numbers(input_value)</code> to <code>expected_output</code>.</p>
<p>This approach is more efficient and ensures the function behaves as expected across a variety of cases.</p>
<h3 id="heading-4-pytest-plugins">4. pytest Plugins</h3>
<p>Plugins are an extension mechanism that allows you to add new functionality to pytest or modify its existing behaviour. These plugins work by providing additional features that extend pytest’s capabilities, which can be useful, especially in complex test scenarios.</p>
<p>pytest has a vast ecosystem of plugins, each designed to suit your different testing needs. You can find the full list of available plugins on <a target="_blank" href="https://pypi.org/">PyPI</a> in the <a target="_blank" href="https://docs.pytest.org/en/stable/reference/plugin_list.html#plugin-list">pytest Plugin List</a>.</p>
<p>To use a plugin, simply install it with <code>pip</code>.</p>
<p><strong>For example:</strong></p>
<pre><code class="lang-python">pip install pytest-NAME
pip uninstall pytest-NAME
</code></pre>
<p><strong>Note:</strong> <code>NAME</code> in the code above should be replaced with the name of the plugin you want to install.</p>
<p>After installing a plugin, pytest automatically finds and integrates it. There’s no need for any additional configuration.</p>
<p>In this section, we explored some of pytest's advanced features. By leveraging these features, you can now significantly improve the quality of your tests by ensuring they’re more efficient, scalable, and easier to maintain over time.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you’ve learned the basics of testing with pytest, from writing and interpreting tests to handling exceptions and using advanced features like fixtures and parametrization.</p>
<p>Whether your code is written manually or generated by AI, learning how to write tests empowers you to detect bugs early, and build more reliable software. Testing acts as a safety net that boosts you confidence during development and ensures your code works as expected.</p>
<p>If you're ready to go a step further, I’ve written an in-depth article on <a target="_blank" href="https://judeolowo.hashnode.dev/test-driven-development-in-python-a-complete-guide-to-unittest">Test Driven Development in Python</a>. It is a powerful approach where writing tests guides your entire coding process.</p>
<p>If you found this helpful, let me know, share it with your network, or give it a like to help others discover it too.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Software Design Basics: Key Phases and Best Practices ]]>
                </title>
                <description>
                    <![CDATA[ Coding has become one of the most common tasks in modern society. With computers now central to almost every field, more people are designing algorithms and writing code to solve various problems. From healthcare to finance, robust software systems p... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-software-design-basics/</link>
                <guid isPermaLink="false">67cb6446f54b40e1e9144db0</guid>
                
                    <category>
                        <![CDATA[ software design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ System Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Coding Best Practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Soham Banerjee ]]>
                </dc:creator>
                <pubDate>Fri, 07 Mar 2025 21:25:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741188275855/9858518f-38c0-4e3b-8be1-7c56b68c77a7.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Coding has become one of the most common tasks in modern society. With computers now central to almost every field, more people are designing algorithms and writing code to solve various problems.</p>
<p>From healthcare to finance, robust software systems power our daily operations, making good software design essential to avoid inefficiencies and bottlenecks. This involves not just writing code but also designing systems that are easy to scale, maintain, and debug, while allowing others to contribute effectively.</p>
<p>Inefficient or ineffective software design can lead to significant issues, like scope creep, miscommunication within teams, project delays, resource misallocation, and complex systems that are difficult to maintain or understand. Without a strong design, teams often accumulate technical debt, which hinders long-term progress and increases maintenance costs.</p>
<p>This article will introduce you to key software design elements that will help you and your team address these challenges and guide you in building efficient, scalable systems. By understanding and applying these elements correctly, you can set up a project for both short-term and long-term success.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>I’ll explain these concepts through examples, but a basic understanding of programming in any language is required for this article (knowledge of Python will be especially beneficial).</p>
<h2 id="heading-scope"><strong>Scope</strong></h2>
<p>The article will introduce key software design elements and explain them using an example. While I won’t provide a full software design for the example problem, I will include enough details to effectively illustrate each design element.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-overview-of-key-software-design-elements">Overview of Key Software Design Elements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-walkthrough-of-the-software-design-process">A Walkthrough of the Software Design Process</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-problem-statement">Problem Statement</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases">Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-requirements">Requirements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-high-level-system-architecture">High Level System Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-detailed-software-design-and-component-breakdown">Detailed Software Design and Component Breakdown</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion-the-value-of-thoughtful-software-design">Conclusion: The Value of Thoughtful Software Design</a></p>
</li>
</ul>
<h2 id="heading-overview-of-key-software-design-elements"><strong>Overview of Key Software Design Elements</strong></h2>
<p>To fully understand the benefits of the software design process, you’ll need to understand some key elements and their scope.</p>
<p>Once you have a good grasp of these, the next step is to define them for the specific problem at hand. Accurately defining these elements reduces risks and simplifies the implementation phase.</p>
<p>Doing this groundwork before implementation helps prevent late discoveries, minimizes the need for rewriting, and makes sure that the design can handle constraints and corner cases.</p>
<p>Now let’s briefly go over the key elements of the software design process:</p>
<ol>
<li><p><strong>Creating a problem statement</strong>: This step involves creating a clear and concise description of the problem that needs to be solved, along with its scope. The scope is essential because it focuses on the exact problem to be addressed and includes assumptions that must be considered during design.</p>
</li>
<li><p><strong>Identifying use cases</strong>: This step outlines all possible user interactions with the software to achieve the desired outcome. It is a critical input to the architecture, as it helps create a design that addresses both general and edge-case use cases.</p>
</li>
<li><p><strong>Stating requirements</strong>: This step defines the expectations of the software, such as its limitations, behaviors, and capabilities for different use cases.</p>
</li>
<li><p><strong>Designing the architecture</strong>: This step provides a high-level structure of the software design, focusing on how to meet the requirements. The architecture typically includes components, how they interact, and how data flows through the system.</p>
</li>
<li><p><strong>Drafting a detailed design</strong>: This step refines the high-level architecture into detailed, component-specific designs, ready for implementation.</p>
</li>
</ol>
<p>In addition to these core elements, there are two important factors you need to consider throughout the design phase.</p>
<p>First, you’ll need to identify and state any assumptions you have. Assumptions can be present at any stage in the design process. Making correct assumptions increases the likelihood of success, improves focus, and reduces complexity in the design.</p>
<p>Second, you’ll need to create good documentation. Documentation is one of the most important elements in the software design process. It’s essential to document each stage as you go along. Documentation serves as the only formal record of the software design and is invaluable for presentations to management, for onboarding new team members, and for anyone returning to the project after a break. It saves valuable time and ensures continuity, as we often overestimate our own memory.</p>
<p>The figure below provides a visual summary of the key software design elements discussed in this section.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738540359869/2ee49614-84b1-439a-ae7e-af637c0f34dd.png?auto=compress,format&amp;format=webp" alt="Figure 1: Key software design elements" width="2244" height="402" loading="lazy"></p>
<p>Next, we’ll apply these key software design elements to a practical example, demonstrating how each element contributes to building a robust and scalable system.</p>
<h2 id="heading-a-walkthrough-of-the-software-design-process"><strong>A Walkthrough of the Software Design Process</strong></h2>
<p>In any well-structured software project, clearly defining the problem is the first crucial step before diving into design and implementation. A well-defined problem ensures that the software meets user needs, remains maintainable, and scales effectively over time.</p>
<p>For this walkthrough, we will focus on designing a financial expense categorization system that processes and analyzes transaction data. This system is a part of a larger financial management solution and needs to be easy to debug, maintain, and scale.</p>
<h3 id="heading-problem-statement"><strong>Problem Statement</strong></h3>
<p>The problem statement provides a high-level goal for the software that we’ll design.</p>
<p>For this example, here’s our statement: Design a software solution that categorizes monthly expenses and generates a report from a list of transactions.</p>
<h4 id="heading-define-the-scope"><strong>Define the scope</strong></h4>
<p>Defining the scope clarifies the smaller tasks that must be accomplished to meet the high-level goal. It outlines the focus of the software design and includes some assumptions.</p>
<p>Includes:</p>
<ol>
<li><p>Implementing a parser to process a list of transactions provided as input.</p>
</li>
<li><p>Filtering transactions for a given month.</p>
</li>
<li><p>Analyzing, categorizing, and generating a report for each expense category.</p>
</li>
</ol>
<p>Excludes:</p>
<p>Performance and memory optimization (excluded due to the limited scope of this article). While performance and memory optimizations are not the primary focus here, it’s important to keep future scalability in mind. Small design choices made now, such as selecting data structures, can help avoid significant refactoring later when the system grows.</p>
<p>Assumptions:</p>
<ol>
<li><p>The list of transactions will be provided as a CSV file in the following format:<br> Columns: "Date, Description, Amount, Type, Category Label".</p>
</li>
<li><p>Expense categories will be provided as input through a JSON file.</p>
</li>
<li><p>The software will run in a shell environment, and inputs will be taken as command-line arguments.</p>
</li>
</ol>
<p>Now that the scope is clear, let’s examine how users will interact with the system through various use cases.</p>
<h3 id="heading-use-cases"><strong>Use Cases</strong></h3>
<p>Use cases define how users will interact with the system to accomplish specific goals. Identifying accurate and valid use cases is critical to creating comprehensive requirements. Failing to capture enough use cases can lead to a design that is incomplete and lacks robustness. This may result in the need for redesigns, which increases time and resource consumption.</p>
<p>On the other hand, identifying too many use cases without considering their feasibility can lead to overly complex designs that are difficult to maintain and implement in the short term.</p>
<p>For our specific problem, the user will need to provide the following inputs while running the software in a shell:</p>
<ol>
<li><p>A CSV file containing a list of transactions.</p>
</li>
<li><p>A month number.</p>
</li>
<li><p>A JSON file containing expense categories.</p>
</li>
</ol>
<p>We need to consider all possible ways the user can interact with the script to achieve the desired outcome. For each of the three inputs, there are two possibilities: valid input or invalid input. This gives us 8 potential use cases (2 possibilities per input: valid and invalid). It's important to define what constitutes valid and invalid inputs for this problem:</p>
<ul>
<li><p>CSV File: Valid if it is in the format described in Assumption 1 (columns: "Date, Description, Amount, Type, Category Label").</p>
</li>
<li><p>Month Number: Valid if the value is between 1 and 12.</p>
</li>
<li><p>JSON File: Valid if it contains expense categories in the correct JSON format.</p>
</li>
</ul>
<p>An input is invalid if it doesn't meet these definitions or if the input is absent.</p>
<p>It’s also crucial to consider the correlation between inputs when evaluating the feasibility of certain use cases, as they may interact with each other in unforeseen ways. Based on these use cases, we can now define the specific requirements that the system must meet.</p>
<h3 id="heading-requirements"><strong>Requirements</strong></h3>
<p>Now, let’s define the expected behaviors, limitations, and capabilities for each use case. Requirements serve as the foundation for architecture, specifications, and implementation. Based on our problem statement, the software will need to accomplish the following tasks:</p>
<ol>
<li><p>The script shall take three inputs: a CSV file of transactions, a month number, and a JSON file of expense categories.</p>
</li>
<li><p>The script shall verify all inputs.</p>
</li>
<li><p>The script shall throw an error and exit if the CSV file cannot be opened or if it does not match the format in Assumption 1.</p>
</li>
<li><p>The script shall throw an error and exit if the JSON file cannot be opened.</p>
</li>
<li><p>The script shall throw an error if the month number is not between 1 and 12.</p>
</li>
<li><p>The script shall parse each transaction and load it into a data structure.</p>
</li>
<li><p>The script shall filter transactions by the specified month.</p>
</li>
<li><p>The script shall load the expense categories from the JSON file into a data structure.</p>
</li>
<li><p>The script shall categorize transactions based on the category label provided in the CSV file.</p>
</li>
<li><p>The script shall throw an exception if a category label in the CSV file is not present in the expense categories.</p>
</li>
<li><p>The script shall use a categorizing function to assign transactions to categories from the JSON file.</p>
</li>
<li><p>A class shall encapsulate categorized transactions, providing APIs to modify or access them.</p>
</li>
<li><p>The script shall support statistics calculation and report generation for categorized transactions.</p>
</li>
</ol>
<p>With the requirements in place, we can now design a high-level architecture to meet those needs.</p>
<h3 id="heading-high-level-system-architecture"><strong>High Level System Architecture</strong></h3>
<p>In this stage, we will design the system at a high level, much like creating a master plan. Architecture involves organizing the software's functions into distinct components, illustrating how they interact, and mapping the flow of control and data through the system. While designing the architecture in this tutorial, we’ll incorporate good design principles.</p>
<p>For this example, the high-level requirements include:</p>
<ol>
<li><p>Loading inputs and verifying them.</p>
</li>
<li><p>Applying time-based filtering.</p>
</li>
<li><p>Categorizing transactions based on category labels and descriptions.</p>
</li>
<li><p>Managing categorized transactions in a finance registry.</p>
</li>
<li><p>Generating reports from the categorized data.</p>
</li>
</ol>
<p>One important component of software architecture is telemetry. Telemetry gathers data on the software's behavior, which is invaluable for debugging and performance assessment in real-world environments.</p>
<p>For smaller systems, simpler logging mechanisms may be sufficient to track basic errors and monitor performance. The decision to implement telemetry should depend on the complexity of the system and operational requirements.</p>
<p>Since telemetry provides such a helpful feedback loop for improving the design in future iterations, we’ll add it to the list of components here.</p>
<p>We’ll build our system architecture around a Test-Driven Development (TDD) approach. We’ll design each component with testing in mind to ensure it meets our requirements.</p>
<p>Just keep in mind that while TDD is a strong practice for ensuring code quality, it may not be the best fit for all projects. In scenarios where you need rapid prototyping or exploratory development, testing might be prioritized after initial iterations. Balancing between TDD and other methodologies depends on the project context and team preferences.</p>
<p>Our architecture will follow a modular structure, meaning the system will be divided into self-contained components. Each component will be responsible for specific functionality, making the system easier to test, maintain, and scale.</p>
<p>To achieve this, the architecture will emphasize loose coupling between components. Each component will interact with others through well-defined interfaces or APIs, ensuring minimal dependencies. We’ll abstract and encapsulate internal implementation details, exposing only the necessary information for interaction. Also, each component will handle its own errors and exceptions to ensure robustness and fault isolation.</p>
<p>But it is also important to consider a centralized error-handling strategy in some cases. Centralizing error handling can reduce redundancy, improve consistency, and make maintenance easier. The choice between local and centralized error handling should depend on the system's complexity and how components interact. This will contribute to the overall scalability and maintainability of the system.</p>
<p>Below is a summary of each component's functionality in this architecture:</p>
<ul>
<li><p>Load and verify input: This component will take the CSV file, JSON file, and month number as input, verify their validity, and load the data into structures.</p>
</li>
<li><p>Time-based filter: This component will filter transactions based on the input month and store the filtered transactions in a data structure.</p>
</li>
<li><p>Label-based categorization: This component will categorize transactions based on the category label in the CSV file.</p>
</li>
<li><p>Description-based categorization: This component will categorize transactions using an algorithm based on the transaction description.</p>
</li>
<li><p>Finance registry: This component will store all categorized transactions for further processing. It isolates the post-processing of categorized transactions from the categorization process and provides methods for updating or retrieving datasets.</p>
</li>
<li><p>Report generation: This component will generate expense reports from the categorized transaction data.</p>
</li>
<li><p>Telemetry: This component will monitor the performance of other components. It will track the flow of transactions, ensuring that all transactions are categorized either by label or description. Additional parameters can be added as needed to monitor specific functionalities.</p>
</li>
</ul>
<p>The diagram below demonstrates the flow of data through these components:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738540585066/6236b867-8c57-4a04-b5ea-4f9dd7f1fef3.png?auto=compress,format&amp;format=webp" alt="Figure 2: Flow of data through various components defined in the architecture" width="2360" height="794" loading="lazy"></p>
<h3 id="heading-detailed-software-design-and-component-breakdown"><strong>Detailed Software Design and Component Breakdown</strong></h3>
<p>While we won't cover the full system design, this section will highlight key components and their specifications. For this example, I will assume the role of both the designer and implementer of the software.</p>
<p>Software design and specifications depend on several factors, including the designer's knowledge, skill set, available time, and resources. We’ll define some of the design details for the system, starting with the choice of the implementation language.</p>
<p>Choosing the right language is based on several important factors:</p>
<ol>
<li><p>The language must meet the software requirements.</p>
</li>
<li><p>It should be stable, and have strong support from an active developer community.</p>
</li>
<li><p>Additional considerations include performance (speed and memory), scalability (ability to grow with future requirements), and platform support (ability to run on all major operating systems).</p>
</li>
</ol>
<p>If you’re the one implementing this design, you’ll need to be familiar with and confident using that programming language. For this project, I chose Python because it meets all the project requirements, has a robust developer community for support, it’s stable, and I’m confident in using it to complete the implementation successfully.</p>
<h4 id="heading-data-structures"><strong>Data Structures</strong></h4>
<p>Now, let’s look at the fundamental data structures that we’ll use in the design. We need to load the contents of the CSV file into a data structure for further analysis and processing. In Python, the Pandas DataFrame from the Pandas library is ideal for analyzing and processing tables, so we will use it to store the transactions.</p>
<p>For generating report, we will encapsulate categorized transactions along with relevant statistics, such as the total number of transactions, mean amount, and maximum amount, within a dedicated dataset class. This approach ensures a clear separation of concerns, where the dataset class manages data processing, while the reporting component focuses on presentation.</p>
<p>By structuring the system this way, we enhance reusability, maintainability, and scalability, making it easier to extend and modify in the future.</p>
<p>This dataset class will include:</p>
<ul>
<li><p>Member variables: category name, category description, a Pandas DataFrame for transactions, total number of transactions, mean amount, and max amount of transactions.</p>
</li>
<li><p>Member functions: set/get DataFrame, save dataset to CSV (useful for debugging).</p>
</li>
</ul>
<p>Here’s an example of a Dataset class in Python for structured data management and processing:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd  <span class="hljs-comment"># Import Pandas for data handling</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dataset</span>:</span>
    <span class="hljs-string">"""
    A class representing a structured dataset with a name, predefined keys, 
    and a Pandas DataFrame.
    """</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, keys</span>):</span>
        <span class="hljs-string">"""
        Initializes the Dataset object.

        Parameters:
        name (str): The name of the dataset.
        keys (list): A list of expected column names for the dataset.

        Attributes:
        self.name (str): Stores the dataset name as a string.
        self.keys (list): Stores the expected column names for data organization.
        self.mean_amt (float): Tracks the mean (average) transaction amount.
        self.max_amt (float): Tracks the maximum transaction amount.
        self.count (int): Stores the total number of transactions in the dataset.
        self.dataframe (pd.DataFrame): A Pandas DataFrame initialized with the specified column names.
        """</span>
        self.name = str(name)  <span class="hljs-comment"># Convert and store dataset name as a string</span>
        self.keys = keys  <span class="hljs-comment"># Store expected column names for consistency</span>
        self.mean_amt = <span class="hljs-number">0</span>  <span class="hljs-comment"># Initialize mean transaction amount to zero</span>
        self.max_amt = <span class="hljs-number">0</span>  <span class="hljs-comment"># Initialize max transaction amount to zero</span>
        self.count = <span class="hljs-number">0</span>  <span class="hljs-comment"># Initialize transaction count to zero</span>
        self.dataframe = pd.DataFrame(columns=keys)  <span class="hljs-comment"># Initialize empty DataFrame with predefined columns</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getName</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Returns the name of the dataset.

        Returns:
        str: The name of the dataset.
        """</span>
        <span class="hljs-keyword">return</span> self.name  <span class="hljs-comment"># Fixed: Removed incorrect parentheses</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getValue</span>(<span class="hljs-params">self, key</span>):</span>
        <span class="hljs-string">"""
        Retrieves a specific column from the DataFrame.

        Parameters:
        key (str): The column name to retrieve.

        Returns:
        pandas.Series or None: The column data if the key exists, otherwise None.
        """</span>
        <span class="hljs-keyword">if</span> key <span class="hljs-keyword">in</span> self.dataframe.columns:
            <span class="hljs-keyword">return</span> self.dataframe[key]
        <span class="hljs-keyword">else</span>:
            print(<span class="hljs-string">f"Warning: Key '<span class="hljs-subst">{key}</span>' not found in DataFrame."</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>  <span class="hljs-comment"># Prevents KeyError</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getKeys</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Returns the list of expected keys (column names) of the dataset.

        Returns:
        list: The keys defining the dataset.
        """</span>
        <span class="hljs-keyword">return</span> self.keys

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setDataFrame</span>(<span class="hljs-params">self, dataframe</span>):</span>
        <span class="hljs-string">"""
        Sets the dataset's DataFrame while ensuring it contains only expected keys.

        Parameters:
        dataframe (pandas.DataFrame): The DataFrame to assign to the dataset.
        """</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> isinstance(dataframe, pd.DataFrame):
            <span class="hljs-keyword">raise</span> TypeError(<span class="hljs-string">"Provided data is not a valid pandas DataFrame."</span>)

        <span class="hljs-comment"># Ensure only the expected columns are included</span>
        self.dataframe = dataframe[self.keys].copy() <span class="hljs-keyword">if</span> set(self.keys).issubset(dataframe.columns) <span class="hljs-keyword">else</span> dataframe.copy()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getDataFrame</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Returns the DataFrame associated with the dataset.

        Returns:
        pandas.DataFrame: The dataset's DataFrame.
        """</span>
        <span class="hljs-keyword">return</span> self.dataframe

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">save_to_csv</span>(<span class="hljs-params">self, file_name</span>):</span>
        <span class="hljs-string">"""
        Saves the dataset's DataFrame to a CSV file.

        Parameters:
        file_name (str): The name of the CSV file to save.
        """</span>
        self.dataframe.to_csv(file_name, mode=<span class="hljs-string">'w'</span>, index=<span class="hljs-literal">False</span>)  <span class="hljs-comment"># Save the DataFrame to CSV</span>
</code></pre>
<p>In the previous section, we outlined the high-level system architecture, detailing the core components and their interactions. Now, let’s dive into the detailed design of some of the individual components, specifying how we’ll implement each one and how it’ll function within the system. We’ll also break down the components to explain how they work together to process the input and generate the report.</p>
<p>Below, you can see the flow diagram for the software, illustrating the interaction between the core components and the flow of data through the system.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739209441033/60142953-c1f4-4146-b64e-c042039e1ef6.png?auto=compress,format&amp;format=webp" alt="Figure 3 Software Flow Diagram" width="1940" height="1128" loading="lazy"></p>
<h4 id="heading-category-label-based-filtering-component"><strong>Category Label-Based Filtering Component</strong></h4>
<p>The Category Label-Based Filtering Component classifies transactions by matching their "Category Label" with predefined expense categories from a JSON file. Transactions with valid category labels are stored in the finance registry, while unmatched ones remain for further processing.</p>
<ul>
<li><p>Input: DataFrame of time-filtered transactions, expense categories from JSON.</p>
</li>
<li><p>Libraries used: Pandas DataFrame.</p>
</li>
<li><p>Software design: Filters transactions based on the "Category Label" column and assigns them to corresponding categories. Transactions that cannot be categorized remain for further processing.</p>
</li>
<li><p>Output: DataFrame of remaining transactions with empty values in the "Category Label" field.</p>
</li>
<li><p>Component tests: Validate handling of valid, invalid, and missing category labels.</p>
</li>
</ul>
<h4 id="heading-finance-registry-component"><strong>Finance Registry Component</strong></h4>
<p>The Finance Registry Component manages categorized transactions by storing them as datasets for each expense category. It maintains a structured collection of DataFrames, each containing transactions and summary statistics such as total count, max amount, and mean amount.</p>
<ul>
<li><p>Input: Expense categories from JSON.</p>
</li>
<li><p>Libraries used: Pandas DataFrame.</p>
</li>
<li><p>Software design: Implements a class that organizes datasets for all expense categories, providing methods to set and retrieve DataFrames.</p>
</li>
<li><p>Component tests: Validate dataset creation, ensuring correct storage and retrieval of categorized transactions.</p>
</li>
</ul>
<p>Here’s a simple and efficient Finance Registry implementation in Python for managing categorized financial datasets:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Dataset <span class="hljs-keyword">import</span> Dataset
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd  <span class="hljs-comment"># Ensure Pandas is imported if used elsewhere</span>

<span class="hljs-comment"># Define column structure for datasets</span>
KEYS = (<span class="hljs-string">"Date"</span>, <span class="hljs-string">"Description"</span>, <span class="hljs-string">"Amount"</span>, <span class="hljs-string">"Transaction Type"</span>, <span class="hljs-string">"Category"</span>, <span class="hljs-string">"Account Name"</span>, <span class="hljs-string">"Labels"</span>, <span class="hljs-string">"Notes"</span>)

<span class="hljs-comment"># Define dataset names for different financial categories</span>
EXAMPLE_DATASET_NAMES = (<span class="hljs-string">"Investment"</span>, <span class="hljs-string">"Expense"</span>, <span class="hljs-string">"Savings"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FinanceRegistry</span>:</span>
    <span class="hljs-string">"""
    A class to manage categorized financial datasets, including investment, expense, and savings datasets.
    This registry allows structured access to transaction data and maintains aggregated financial metrics.
    """</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Initializes the FinanceRegistry object.

        Attributes:
        self.example_dataset (dict): A dictionary storing Dataset objects for financial datasets.
        """</span>
        self.example_dataset = {name: Dataset(name, KEYS) <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> EXAMPLE_DATASET_NAMES}  <span class="hljs-comment"># Create datasets for categories</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setExampleDatasetToRegistry</span>(<span class="hljs-params">self, name, dataframe</span>):</span>
        <span class="hljs-string">"""
        Merges a new dataframe into the existing dataset for a given financial category.

        Parameters:
        name (str): The category name (e.g., "Investment", "Expense", or "Savings").
        dataframe (pd.DataFrame): The new data to be added.

        If the dataset already contains data, it concatenates the new dataframe to the existing one.

        Raises:
        ValueError: If the provided name is not a valid dataset category.
        """</span>
        <span class="hljs-keyword">if</span> name <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> self.example_dataset:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Invalid dataset name: '<span class="hljs-subst">{name}</span>'. Expected one of <span class="hljs-subst">{EXAMPLE_DATASET_NAMES}</span>"</span>)

        df = self.example_dataset[name].getDataFrame()  <span class="hljs-comment"># Get existing dataset</span>

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> dataframe.empty:  <span class="hljs-comment"># Ensure the new dataframe is not empty</span>
            dataframe = pd.concat([df, dataframe], axis=<span class="hljs-number">0</span>, ignore_index=<span class="hljs-literal">True</span>)  <span class="hljs-comment"># Append new data</span>

        self.example_dataset[name].setDataFrame(dataframe)  <span class="hljs-comment"># Update dataset in registry</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getExampleDatasetFromRegistry</span>(<span class="hljs-params">self, name</span>):</span>
        <span class="hljs-string">"""
        Retrieves the dataset for a given financial category.

        Parameters:
        name (str): The category name (e.g., "Investment", "Expense", or "Savings").

        Returns:
        Dataset: The dataset corresponding to the given name.

        Raises:
        ValueError: If the provided name is not a valid dataset category.
        """</span>
        <span class="hljs-keyword">if</span> name <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> self.example_dataset:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Invalid dataset name: '<span class="hljs-subst">{name}</span>'. Expected one of <span class="hljs-subst">{EXAMPLE_DATASET_NAMES}</span>"</span>)

        <span class="hljs-keyword">return</span> self.example_dataset[name]
</code></pre>
<p>The diagram below illustrates how the Finance Registry organizes these datasets for further processing in the Report Generation component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739209411075/7a772e4f-9687-4c96-8995-10a70e27a36d.png?auto=compress,format&amp;format=webp" alt="Figure 4 Finance Registry datasets for expense category" width="1850" height="864" loading="lazy"></p>
<h4 id="heading-report-generation-component"><strong>Report Generation Component</strong></h4>
<p>The Report Generation Component processes categorized transaction datasets from the finance registry and generates summary statistics. It calculates key financial metrics such as maximum amount, mean amount, and total transaction count. It also provides functionality to display categorized transactions in a structured format within the shell.</p>
<ul>
<li><p>Input: Datasets of categorized transactions from the finance registry.</p>
</li>
<li><p>Libraries used: Numpy for calculations, Tabulate for formatted shell output (if needed).</p>
</li>
<li><p>Software design: Implements a class with methods to compute financial statistics and display transaction summaries per expense category.</p>
</li>
<li><p>Component tests: Validate correct calculation of mean, max, and total transactions, and ensure accurate display of categorized datasets in the shell.</p>
</li>
</ul>
<p>Here’s a function to compute transaction statistics, including mean, max, and count, from a dataset in the report generation component:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Dataset <span class="hljs-keyword">import</span> Dataset
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculateStats</span>(<span class="hljs-params">dataset</span>):</span>
    <span class="hljs-string">"""
    Computes statistical metrics for a given dataset.

    Parameters:
    dataset: The dataset containing transaction data.

    Updates:
    - dataset.mean: Mean transaction amount.
    - dataset.max: Maximum transaction amount.
    - dataset.count: Number of transactions.
    """</span>

    <span class="hljs-comment"># Return early if the dataset has no transactions</span>
    <span class="hljs-keyword">if</span> dataset.dataframe.empty:
        <span class="hljs-keyword">return</span>

    <span class="hljs-comment"># Extract transaction amounts as a list</span>
    tx_amount_list = dataset.dataframe[<span class="hljs-string">'Amount'</span>].astype(float).round(<span class="hljs-number">2</span>).tolist()

    <span class="hljs-comment"># Adjust transaction amounts based on "Transaction Type"</span>
    <span class="hljs-keyword">for</span> i, tx_type <span class="hljs-keyword">in</span> enumerate(dataset.dataframe[<span class="hljs-string">'Transaction Type'</span>]):
        <span class="hljs-keyword">if</span> tx_type == <span class="hljs-string">'debit'</span>:
            tx_amount_list[i] *= <span class="hljs-number">-1</span>  <span class="hljs-comment"># Convert debit transactions to negative values</span>

    <span class="hljs-comment"># Compute statistical metrics</span>
    dataset.mean = round(np.mean(tx_amount_list), <span class="hljs-number">2</span>)
    dataset.max = max(tx_amount_list)
    dataset.count = len(tx_amount_list)
</code></pre>
<p>This concludes the design section, where we explored key software design elements with a practical example. The next step, implementation, is beyond the scope of this article. But it's crucial to recognize that new challenges often emerge during development, requiring updates to requirements, architecture, and specifications.</p>
<p>The purpose of this article is not to provide a full implementation, but to teach you some basic software design principles through an example. The focus is on understanding how to structure software, define clear requirements, and create scalable architectures, all before writing code.</p>
<p>By following a structured design process, you can shift complex problem-solving from implementation to the architecture phase, where you can explore solutions more effectively using flowcharts, block diagrams, and documentation. This makes the development process more organized, efficient, and maintainable, a crucial skill for real-world software engineering.</p>
<p>If you're learning to code, remember that good design is just as important as writing code itself!</p>
<h2 id="heading-conclusion-the-value-of-thoughtful-software-design"><strong>Conclusion: The Value of Thoughtful Software Design</strong></h2>
<p>With well-defined problem statements, scope, requirements, specifications, and design, even complex problems can be solved and maintained in a sustainable way.</p>
<p>The steps we went through in this article can help you break down any problem, regardless of its complexity, into smaller, actionable tasks that you and your team can efficiently tackle.</p>
<p>Without proper planning, projects are often plagued by scope creep, wasted time and resources, miscommunication between teams, overly complicated designs, technical debt, and frequent redesigns.<br>Good design is often simple design, but achieving simplicity is difficult without thorough planning.</p>
<p>Approaching each problem with the mindset of defining a Problem Statement, Scope, Use Cases, Requirements, Architecture, and Specifications helps cultivate a strong software design mindset. This mindset is crucial for developing software that is scalable, maintainable, and high quality.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Test Driven Development in Android Apps – A Practical Guide to TDD ]]>
                </title>
                <description>
                    <![CDATA[ By Siamak Mahmoudi TDD, or Test-Driven Development, is a software development approach where tests are written before the actual code is implemented.  It requires a clear understanding of "What" and "How" in the the requirements of the project/featur... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/tdd-in-android-apps/</link>
                <guid isPermaLink="false">66d85255c1231da2ef2b5a9c</guid>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 06 Sep 2023 06:34:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/TDD--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Siamak Mahmoudi</p>
<p>TDD, or Test-Driven Development, is a software development approach where tests are written before the actual code is implemented. </p>
<p>It requires a clear understanding of "What" and "How" in the the requirements of the project/feature. </p>
<p>TDD helps to write less, but enough code. It helps prevent common software development mistakes, such as over-engineering,  too much test coverage, missing main requirements, too large functions and classes, and too many complicated code statements. </p>
<p>Overall, it helps to have a concise, already unit-test covered, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-write-clean-code/">clean</a> codebase. Over time, it also saves development and code maintenance costs.</p>
<p>In this article we will discuss TDD in action. </p>
<p>The context is an Android development environment, so we will use Kotlin and JUnit5 with a sample project to demonstrate the steps. </p>
<p>However, the instructions and techniques here can be practiced in other programming languages as well.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Basic knowledge of <a target="_blank" href="https://www.freecodecamp.org/news/learn-kotlin-complete-course/">Kotlin</a> </li>
<li>Basic knowledge of writing Unit tests</li>
<li>Knowledge of mocks and assertions</li>
</ul>
<p>We will use Kotlin as the programming language and <a target="_blank" href="https://junit.org/junit5/">JUnit5</a> to write unit tests.</p>
<p> <a target="_blank" href="https://site.mockito.org/">Mockito</a> will be used to work with mocks and <a target="_blank" href="https://www.danywalls.com/how-and-when-to-use-mocks-or-spies-on-unit-testing">spys</a>.</p>
<p>The target audience is any software developer from any platform seeking a new chapter in their career. </p>
<p>Even though the context is Android, the content does not talk about platform specific properties. Instead, we focus on techniques, notes and challenges when developing with TDD.</p>
<p>If above is OK with you, let's get started.</p>
<h2 id="heading-how-test-driven-development-works">How Test Driven Development Works</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-232.png" alt="Image" width="600" height="400" loading="lazy">
<em>TDD Cycle</em></p>
<p>The development process follows a cycle of:</p>
<ol>
<li>Writing a failing test (pink square).</li>
<li>Implementing the code to make the test pass (green square)</li>
<li>Refactoring the code (blue square) as needed while ensuring that the tests continue to pass (pale green square).</li>
<li>Writing a new failing test (restart the flow again)</li>
</ol>
<h3 id="heading-writing-a-failing-test-pink-square">Writing a Failing Test (Pink Square)</h3>
<p>In this step, you start by describing what you want your code to do. </p>
<p>Imagine you're giving your code a test to check if it behaves correctly. This test is like a question you ask your code, such as "Can you do this task?" </p>
<p>At first, your code doesn't know the answer, so you write a test that should fail because your code doesn't know how to do the task yet. This failing test is like a pink warning sign that tells you something isn't right.</p>
<p>Once you've finished this stage, JUnit5 will generate a comprehensive report from the tests you've crafted. These tests will stand as a tangible representation of your work. </p>
<p>Now, imagine that your project manager is reading these test cases to assess both their coverage and the accuracy of your grasp on the feature or product. Embracing this perspective offers a clearer understanding of the significance of this developmental phase.</p>
<p>Shift your focus from technical intricacies to the software's behavior itself. </p>
<p>Instead of getting caught up in the nitty-gritty technical aspects, direct your attention to how the software functions and interacts with users and other components. </p>
<p>This shift in perspective allows you to prioritise the software's intended actions and outcomes, leading to tests that accurately reflect its real-world behavior. </p>
<p>By concentrating on behavior rather than technical minutiae, you ensure that your tests align closely with the software's purpose and user expectations. </p>
<p>In some cases, You might end up with no more than a few test cases per component (which is the purpose: less work but targeted) and that's totally fine, as long as you cover all the behavioural requirements of the project.</p>
<h4 id="heading-tips">Tips</h4>
<ul>
<li>Be specific<strong>:</strong> Write clear and specific test cases that focus on one aspect of your code's behavior.</li>
<li>Start simple: Begin with the simplest test case that covers the basic functionality you need.</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> `a sum <span class="hljs-keyword">is</span> calculated from two input numbers`<span class="hljs-params">()</span></span> {}
</code></pre>
<ul>
<li>Use meaningful names: Name your tests descriptively so that anyone reading them knows what the test is checking.</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> `Font Ratio <span class="hljs-keyword">is</span> fetched from <span class="hljs-keyword">data</span> source INITIALLY`<span class="hljs-params">()</span></span> {}
</code></pre>
<h4 id="heading-common-mistakes-to-avoid">Common mistakes to avoid</h4>
<ul>
<li>Testing too much at once<strong>:</strong> Avoid testing multiple things in a single test. This can make it hard to identify what's failing.</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Don't do this</span>
<span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> `pixelSize fits the standart sizes <span class="hljs-keyword">while</span> fontSize <span class="hljs-keyword">is</span> bigger than minumum supported font size but matches the list of special levels of size`<span class="hljs-params">()</span></span> {}
</code></pre>
<ul>
<li>Relying on implementation details<strong>:</strong> Don't write tests that are tightly coupled to the code's inner workings. Tests should focus on behavior, not implementation.</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Don't do this</span>
<span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> `pixelSize <span class="hljs-keyword">is</span> <span class="hljs-built_in">Long</span> and Non-Null and fits the standart sizes then calculated font size <span class="hljs-keyword">is</span> non-<span class="hljs-literal">null</span> and of type Dimention`<span class="hljs-params">()</span></span> {}
</code></pre>
<h3 id="heading-implementing-the-code-to-pass-the-test-green-square">Implementing the Code to Pass the Test (Green Square)</h3>
<p>Now that you have your test in place, it's time to teach your code how to do the task correctly. </p>
<p>You write the actual code that should make the test pass and your code answer the question correctly. </p>
<p>When your code passes the test, it's like a green light saying, "Yes, I can do the task now!". </p>
<p>This step is about making sure your code understands and can solve the problem you're asking it to.</p>
<h3 id="heading-tips-1">Tips</h3>
<ul>
<li>Write minimal code: Write the simplest code that makes the failing test pass. You can read more about how to avoid over-engineering <a target="_blank" href="https://www.rst.software/blog/how-to-avoid-over-engineering">here</a>. </li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Test Case </span>
<span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> `Storage stores font ratio <span class="hljs-keyword">in</span> key-value`<span class="hljs-params">()</span></span> { 

    <span class="hljs-comment">// Given</span>
    <span class="hljs-keyword">val</span> fontRatio = <span class="hljs-number">2.0f</span>
    <span class="hljs-keyword">val</span> mockEditor = mockk&lt;SharedPreferences.Editor&gt;(relaxed = <span class="hljs-literal">true</span>)
    every { mockSharedPreference.edit() } returns mockEditor 
    every { mockEditor.putFloat(any(), any()) } returns mockEditor 
    every { mockEditor.apply() } just Runs 

    <span class="hljs-comment">// When </span>
    storage.saveFontRatio(fontRatio) 

    <span class="hljs-comment">// Then</span>
    verify(exactly = <span class="hljs-number">1</span>) { 
        mockEditor.apply() 
    }
}


<span class="hljs-comment">// Correct Implementation - Avoid extra implementation</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SharedPreferenceHelper</span></span>( 
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> sharedPreferences: SharedPreferences 
) { 
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">saveFontRatio</span><span class="hljs-params">(fontRatio: <span class="hljs-type">Float</span>)</span></span> {
        sharedPreferences.edit().putFloat(<span class="hljs-string">"font-ratio"</span>, fontRatio).apply() 
    } 
}


<span class="hljs-comment">// Wrong Implementation </span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SharedPreferenceHelper</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> sharedPreferences: SharedPreferences
) { 
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">saveFontRatio</span><span class="hljs-params">(fontRatio: <span class="hljs-type">Float</span>)</span></span> { 
    <span class="hljs-keyword">if</span> (fontRatio &lt;= <span class="hljs-number">0.0f</span>) 
    <span class="hljs-keyword">throw</span> IllegalArgumentException(<span class="hljs-string">"Font ratio must be greater than 0.0f"</span>) 

    storeValue(key = FONT_RATIO_KEY, value = fontRatio) 

} 

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">storeValue</span><span class="hljs-params">(key: <span class="hljs-type">String</span>, value: <span class="hljs-type">Float</span>)</span></span>{
        <span class="hljs-keyword">val</span> editor = sharedPreferences.edit() editor.putFloat(key, value)
        editor.apply() 
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getFontRatio</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> { 
    <span class="hljs-keyword">return</span> sharedPreferences.getFloat(<span class="hljs-string">"font_ratio"</span>, <span class="hljs-number">1.0f</span>) } 
}
</code></pre>
<ul>
<li>Avoid duplication<strong>:</strong> Don't repeat code. If you find yourself writing similar logic in multiple places, consider refactoring. This primary code improvements can be done in this phase, but if the modification can have a side-effect then ignore it.</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> ... </span>{
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getDefaultFontSize</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">val</span> zoomRatio = DEFAULT_SSPEED * DEFAULT_FONT_RATIO / deviceDensity 
        <span class="hljs-keyword">val</span> fontSize = zoomRatio * standardFontSize 
        <span class="hljs-keyword">return</span> fontSize 
    }
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getFontSizeBySSpeed</span><span class="hljs-params">(speed: <span class="hljs-type">Int</span>)</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">val</span> zoomRatio = speed * DEFAULT_FONT_RATIO / deviceDensity 
        <span class="hljs-keyword">val</span> fontSize = zoomRatio * standardFontSize 
        <span class="hljs-keyword">return</span> fontSize 
    }
}
</code></pre>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> ... </span>{ 
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getDefaultFontSize</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> = calculate(DEFAULT_AGE)
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getFontSizeByAge</span><span class="hljs-params">(age: <span class="hljs-type">Int</span>)</span></span>: <span class="hljs-built_in">Float</span> = calculate(age) 

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">calculate</span><span class="hljs-params">(age: <span class="hljs-type">Int</span>)</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">val</span> zoomRatio = age * DEFAULT_FONT_RATIO / deviceDensity 
        <span class="hljs-keyword">val</span> fontSize = zoomRatio * standardFontSize 
        <span class="hljs-keyword">return</span> fontSize 
    }
}
</code></pre>
<h4 id="heading-common-mistakes-to-avoid-1">Common mistakes to avoid:</h4>
<ul>
<li>Jumping Ahead: Don't write more code than necessary to pass the test. TDD is about incremental development. TDD encourages an incremental and step-by-step approach to development. When you jump ahead, you're essentially trying to solve problems that are not yet directly related to the current test you're working on. The primary goal is to focus on the immediate task at hand – passing the current test – without getting sidetracked by future functionalities.</li>
<li>Ignoring Test Failures: If a test doesn't fail initially, you might be missing an important case. This might seem unlikely to happen at first sight, but after some development in your test components you'll start writing multiple tests for a single method to test different aspects of the logic. This is where you should not be happy if your unimplemented logic passes the test. In simple words, this is how you catch bugs in development phase. So, expect the failure when it should be.</li>
</ul>
<h3 id="heading-refactoring-the-code-blue-square-and-ensuring-test-success-pale-green-square">Refactoring the Code (Blue Square) and Ensuring Test Success (Pale Green Square)</h3>
<p>Once your code passes the test, it's time to clean things up. </p>
<p>You might see ways to make your code more organised, easier to understand, or even faster. Think of it as tidying up your room once you're done playing, making everything neat and organised after you've finished playing.You improve your code without changing what it does. </p>
<p>As you do this, you keep running all your tests to make sure they still pass. If a test fails during this step, it's like a pale green caution sign telling you that something you cleaned up might have accidentally broken the code.</p>
<p>You can treat this part as a separate code maintenance phase. </p>
<p>Assume that you are given the task to clean up an old code and make sure it follows team code quality guidelines as well as product requirements. </p>
<p>Throughout this process, the key is to maintain a careful balance – refining while ensuring your tests continue to succeed.</p>
<p>Here are some ideas and strategies for the refactoring phase:</p>
<ul>
<li>Code clarity: Simplify complex sections, replace unclear variable names, and enhance comments to make the code easier for others (and your future self) to understand.</li>
<li>Modularity: Break down large functions into smaller, focused ones. This makes your code more modular and allows for easier maintenance and testing.</li>
<li>Remove redundancy: Identify duplicated code and consolidate it into reusable functions or classes. This helps eliminate repetition and ensures consistency.</li>
<li>Optimization: Identify areas where performance can be improved. However, only optimize if you have specific performance goals and evidence that the code is a bottleneck. Optimization here is to avoid resource drain and not to make the code performant.</li>
<li>Consistent formatting: Maintain a consistent code style, adhering to the conventions of your team or project.</li>
<li>Unused code: Remove any unused variables, functions, or imports that clutter the codebase.</li>
<li>Test improvements: Unlike the usual perception regarding TDD, you can add tests whenever there is a need for it. Enhance the test suite by adding new test cases to cover scenarios that weren't previously addressed. This helps maintain comprehensive test coverage.</li>
<li>Documentation: If your code's purpose isn't immediately clear from the code itself, consider adding or improving documentation to explain its intent and usage. Avoid making it a habit. This is meant to act as a complementary explanation for crucial cases to avoid confusion.</li>
</ul>
<p>Note that TDD code should be self-expressing and independent of documentation.</p>
<p>Remember, while refactoring, it's crucial to keep running all your tests to ensure they continue to pass.</p>
<h4 id="heading-tips-2">Tips</h4>
<ul>
<li>Keep tests comprehensive: Make sure your tests cover various scenarios to catch unintended side effects during refactoring.</li>
<li>Refactor gradually: Make small changes to your code and run tests frequently to catch any regressions early.</li>
</ul>
<h4 id="heading-common-mistakes-to-avoid-2">Common mistakes to avoid:</h4>
<ul>
<li>Refactoring without tests<strong>:</strong> Refactoring without having tests in place can lead to unexpected behavior. If there is a chance to miss a part of the logic then consider writing tests for it.</li>
<li>Large code change: Sometimes we end up changing more number of lines than what we developed to make the test pass. Always consider a separate refactoring phase over making too much changes in development phase as it's a safer &amp; less costly option.</li>
</ul>
<h3 id="heading-writing-a-new-failing-test-restarting-the-flow">Writing a New Failing Test (Restarting the Flow)</h3>
<p>Now, you think of the next thing you want your code to do. </p>
<p>You start by writing a new test that should fail because your code doesn't know how to do the new task yet. This is like giving your code a new challenge to solve. </p>
<p>Then, you repeat the whole cycle: make the test pass with code (green square), clean up if needed (blue square), and keep testing to make sure everything works (pale green square). </p>
<p>This way, you're always moving forward and building your code step by step.</p>
<h4 id="heading-tips-3">Tips</h4>
<ul>
<li>Incremental steps: Add new tests for new functionality in small increments to maintain a clear development path. Instead of attempting to implement a complex feature all at once, you break it down into smaller, manageable pieces and create tests for each of these pieces. This approach maintains a clear and steady development path, helping you to stay focused, reduce risks, and ensure that each addition to your software is thoroughly tested.</li>
<li>Feedback loop: Use the feedback from writing failing tests to guide your implementation. Feedback loop highlights the iterative nature of TDD. As you craft new tests and observe them failing, you gain valuable insights that guide your implementation. </li>
</ul>
<p>Here's how the feedback loop works:</p>
<ul>
<li>Expectation setting: When you write a new test, you define your expectations for how the code should behave. This clarifies what you're aiming to achieve with your new feature.</li>
<li>Initial failure: The test fails at first because the corresponding code to fulfill its expectations is missing or incomplete. This initial failure is a natural part of the TDD process.</li>
<li>Guides your implementation: The feedback from the test's failure points you in the direction of what code needs to be written or modified. It becomes a roadmap for your development, outlining what the new functionality should look like.</li>
<li>Incremental Progress: As you implement the necessary code to make the test pass, you're incrementally building up the desired functionality. Each step is guided by the feedback provided by the failing test.</li>
<li>Verification: Once your implementation is complete, you run the test again. If it passes, it verifies that your new code satisfies the expectations you initially set.</li>
</ul>
<p>The feedback loop ensures that your development is tightly aligned with the intended goals of your software.</p>
<h4 id="heading-common-mistakes-to-avoid-3">Common mistakes to avoid:</h4>
<ul>
<li>Writing tests after implementation: Don't write tests after you've implemented the feature. TDD is about writing tests first. Even a tiny piece of logic added before the test code means there is a possible resource waste/bug in the code. The whole point is to not to add any logic unless there is a need for it from test suite.</li>
<li>Skipping failing tests: Don't skip this step even if you think you know how to implement the feature.</li>
</ul>
<p>Here is why you should not skip the failing tests step even when you're confident:</p>
<ul>
<li>Clarity of intent: Writing a failing test clarifies your intent for the feature. It forces you to consider the exact behavior and outcomes you're aiming for before diving into implementation.</li>
<li>Verification of assumptions: Even if you think you understand the feature, creating a test ensures that your assumptions are valid. Your understanding might be correct, but the test validates it.</li>
<li>Safety Net: By writing a failing test, you establish a safety net that prevents regressions in the future. It acts as a specification for the feature and helps catch unintended side effects.</li>
<li>Incremental development: TDD encourages incremental development. Each new feature is built step by step, with a clear progression from failing test to working implementation. Skipping this step disrupts that progression.</li>
<li>Documentation: The failing test documents the expected behavior of the feature. This documentation is valuable for you and your team, especially when revisiting the code in the future. Always remember that there are systems to generate reports by listing out all of your test code for product managers and QAs. Those reports expose the details you spotted in the product, So, try to convince them that you understood the point thoroughly.</li>
</ul>
<h2 id="heading-how-to-develop-using-tdd">How to Develop Using TDD</h2>
<p>TDD emphasises the importance of writing <a target="_blank" href="https://smartbear.com/learn/automated-testing/what-is-automated-testing/">automated tests</a> to drive the design and development of software. This leads to code that is more reliable, maintainable, and easier to change over time.</p>
<p>But how can we put it into practice? By trying it out and getting used to it gradually.</p>
<p>Let's try TDD while developing a new feature to demonstrate how we can start using it in real world.</p>
<p> We will be implementing a font size auto setting feature. </p>
<p>We have a news app and a user can set auto-scroll-speed for news feed. </p>
<p>We want to implement a feature which adjusts the screen font size from the scroll speed set in the User Profile page.</p>
<p>If the user sets the scroll speed from 0 to 1, then the font size should increase by 1.3. </p>
<p>Any scroll speed increment over 1 will result in increase of the font size by 1.2. </p>
<p>This feature allows users to have a better experience while reading the news.</p>
<p>I've also shared the code we explore in <a target="_blank" href="https://github.com/thesiamak/tdd-FontSize">this GitHub repository</a>.</p>
<p> Feel free to clone and play with it.</p>
<p>Try to follow the steps as we progress in the development. This will help you grasp the techniques and the way of thinking in the context of TDD practically. </p>
<p>So, open Android Studio and create a new project.</p>
<h3 id="heading-font-size-auto-setting-feature-data-flow-chart">Font Size Auto Setting Feature Data Flow Chart</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/test--2-.png" alt="Image" width="600" height="400" loading="lazy">
<em>DFD of a sample feature in an android app</em></p>
<p>Above is the flowchart of what the data flow should look like in the end. </p>
<p>Here's an outline of each engaging component:</p>
<p>The <code>AutoScrollSettingsUseCase</code> class will handle the logic for calculating and storing the <code>FontRatio</code> based on the selected Scroll Speed. </p>
<p>This use case will have a dependency on the <code>UserRepository</code> storing the <code>FontRatio</code> value.</p>
<p>In the <code>UserRepository</code>, there are methods to store and retrieve the <code>FontRatio</code> value using the  <code>Storage</code> mechanism. Whenever a new <code>FontRatio</code> is sent to the storage, any observables will receive an emission with the latest value.</p>
<p>In the <code>UserProfileViewModel</code>, there is an instance of the <code>AutoScrollSettingsUseCase</code> that is being called whenever the user updates the Scroll Speed. This will trigger the recalculation of the <code>FontRatio</code> and its stored via the repository.</p>
<p>We will have the necessary UI components in the User Setting section to allow the user to input their desired scroll speed. This can be done using standard Android UI elements such as <code>NumberPicker</code> or custom UI components (We will not discuss these parts).</p>
<p>This is the breakdown for a simple feature and every time you go through it, it becomes more clear what are the steps and the final result. It's crucial to do it for your changes.‌             ‌</p>
<h3 id="heading-how-to-write-the-tests">How to Write the Tests</h3>
<p>The first step is to always create the test class itself. In this case, we will have at least the following test classes:</p>
<ul>
<li><code>UserRepositoryTest</code></li>
<li><code>AutoScrollSettingTest</code> </li>
<li><code>UserSettingsViewModelTest</code></li>
</ul>
<p>I prefer to start with the ViewModel part. </p>
<p>A ViewModel is an Android Architectural component which escapes lifecycle changes (such as foreground, background, focused). So, it's a fine place to store our states. </p>
<p>Let's create the test file inside the <code>unitTest</code> directory of the source code following the same package path as the real feature code.</p>
<p>TDD in practice is dissimilar to legacy work development. </p>
<p>With TDD we use an IDE to boost file and property(fields) creation process. But we create Test files manually! After a few tries, this aspect of IDE will become handy.</p>
<p> Create the code structure (packages) and then create your test class by right clicking on the package and selecting the <code>Class</code> type. </p>
<p>Choose a descriptive name for it (maybe you should follow a convention for it if you're not already). </p>
<p>For instance: <code>xxx is tested for</code>, where <code>xxx</code> is the name of the tested component.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/Screenshot-2023-09-02-at-2.00.39-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Use IDE To Create Files</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/Screenshot-2023-09-02-at-2.01.48-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, let's create empty tests. Try to be as broad as possible. </p>
<p>According to the diagram, we will not have much logic for this feature. </p>
<p>There are two main strategies for writing unit test functions:</p>
<ul>
<li>AAA</li>
<li>Given/When/Then</li>
</ul>
<pre><code class="lang-junit">@Test fun `strategy A`(){ 
    // Arrange
    // Act 
    // Assert 
}

@Test fun `strategy B`(){ 
    // Given 
    // When 
    // Then 
}
</code></pre>
<p>Let's choose one and follow it for all your tests.</p>
<p>The concept is the same: cluster your test code to make is easy to read and maintain.</p>
<p>This is what I have for now:</p>
<pre><code class="lang-junit">class UserProfileViewModel is tested for` {
    // Unimplemented Class 
    val viewModel = UserProfileViewModel()

    @Test
    fun Font Ratio is fetched from data source`(){}

    @Test
    fun `Scroll Speed update is called so fontSize calculations are triggered`() {}

    @Test
    fun `Font Ratio is updated with new emissions from data source`() {}
}
</code></pre>
<p>Let's run the tests!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-9.42.00-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Failed Test Due To a Missing Test Target</em></p>
<p>It's failing. In fact, the build has failed- Not the test. </p>
<p>Congratulations! We just made it to the first step in TDD cycle:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-9.44.08-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>First step in TDD cycle</em></p>
<p>Since the ViewModel does not exist yet, we have red colors. </p>
<p>Now, let's create an instance of the ViewModel, </p>
<p>So, we use an IDE to create a missing class or unimplemented code. </p>
<p>To make this dialog popup, I move the pointer to the unimplemented part and hit Option + Return (on macOS). </p>
<p>Then, follow the provided options:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-9.48.22-PM-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>TDD Action: Create Target Files through UnitTest file</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/Screenshot-2023-09-02-at-2.05.10-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Choose The Correct Destination For The New File</em></p>
<p>And now let's re-run the tests (last step):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-9.52.50-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the test passing</em></p>
<p> Yes! It passed.</p>
<p>Note that these tests have an empty body and they test nothing! That's correct and alright.</p>
<p>We should even continue to create all the test classes (still with an empty test body) for every component in the DFD diagram - I shared  these at the beginning of the article.</p>
<p>This further helps to have a more clear understanding of the feature before we implement it.</p>
<p>Eventually, we will have around 3-4 test classes containing general scenarios and Unit tests to cover. </p>
<p>It will look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/Screenshot-2023-09-02-at-2.07.53-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Minimal Empty Test Cases</em></p>
<p>Let's implement one of them as an example.</p>
<p> But, before that, we are going to need to work with UI and Domain data models of this feature. </p>
<p>So, in order to be able to move the data around, let's create the data classes you need in advance.</p>
<p>Back to our <code>ProfileViewModel</code> test class, we have an empty unit test function. Let's implement that one.</p>
<p>Note that the key here is to read the test carefully and avoid extra implementation neither assertions. </p>
<p>Only the requirement is allowed to be implemented.</p>
<p>In this case, we need a stream of data which is connected to a previously created data source(<code>UserRepository</code>). </p>
<p>Don't forget: We need a Failing Test first.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-11.19.34-PM-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Implement Inner Body</em></p>
<p>Notice the unimplemented parts inside the test function body (marked with red font). </p>
<p>Now, let's implement the code, then refactor it to make it just pass.</p>
<p> I'm using the <a target="_blank" href="https://mockk.io/">MockK</a> library for mocking classes and objects and <a target="_blank" href="https://github.com/cashapp/turbine">Turbine</a> to test Flow streams here.</p>
<p> If you are not familiar with them don't panic! Just check out their official webpage and try them out. </p>
<p>Let's create the dependency first and add it to the ViewModel using <a target="_blank" href="https://kotlinlang.org/docs/functions.html#named-arguments">Named Arguments</a>. Named Argument helps us when creating the parameter via IDE to introduce proper names through the test code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-10.43.23-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create Missing Parameter Using IDE Dialogs</em></p>
<p>Do the same for the <code>FontRatio</code> variable inside the Repository. </p>
<p>Eventually ,the final test code can be something like the code below:</p>
<pre><code class="lang-junit">class `UserProfileViewModel is tested for` {

    init {
        Dispatchers.setMain(Dispatchers.Unconfined)
    }

    val mockUserRepository = mockk&lt;UserRepository&gt;()

    @Test
    fun `Font Ratio is fetched from data source`() = runTest {
        // Given
        val expectedRatio = 2.0f
        every { mockUserRepository.fontRatio } returns flowOf(FontRatioUiModel(expectedRatio))
        val viewModel = UserProfileViewModel(userRepository = mockUserRepository)

        // When
        viewModel.fontRatio.test {
            val fromDataSource = expectItem()

            // Then
            assertEquals(/* expected = */ expectedRatio, /* actual = */ fromDataSource.fontRatio)
        }
    }
...
}
</code></pre>
<p>Note that we don't implement inner parts of the ViewModel or Repository here.</p>
<p>We just create the missing parts to remove error from the test body. </p>
<p>We will implement those details in a next iteration. </p>
<p>Run the test now. </p>
<p>Of course it will fail, because we did not implement <code>FontRatio</code> inside <code>ProfileViewModel</code>. </p>
<p>Now, refactor the ViewModel to make the test pass (minimal implementation). </p>
<p>In this case, just need to connect the state flow to the repository. We already added it as a dependency in the previous iteration. </p>
<p>Here is the final code:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserProfileViewModel</span></span>(
    userRepository: UserRepository
) : ViewModel() {

    <span class="hljs-keyword">val</span> fontRatio: StateFlow&lt;FontRatioUiModel&gt; = userRepository.fontRatio.stateIn(
        initialValue = FontRatioUiModel(DEFAULT_FONT_RATIO),
        scope = viewModelScope,
        started = SharingStarted.Lazily
    )

    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> DEFAULT_FONT_RATIO = <span class="hljs-number">1.0f</span>
    }
}
</code></pre>
<p>Run the test again, And Boom! It passes!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-06-at-11.23.17-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Passing Test After Minimal Implementation Of Main Code</em></p>
<p>With this Unit test, we implemented a primary part of the <code>UserProfileViewModel</code> component. But only the necessary parts. Do the same for the rest of the test cases. </p>
<p>Do not treat these test cases like you do with normal Unit tests (which run and pass quickly). </p>
<p>Spend some time on it to understand the technical and product requirements first. Then, rollout the plan and start implementing. After a few tries, it'll be easier to think the TDD way.</p>
<h3 id="heading-source-code">Source Code</h3>
<p>The <a target="_blank" href="https://github.com/thesiamak/tdd-FontSize">source code</a> and the repository for this project  is available on <a target="_blank" href="https://github.com/thesiamak">my GitHub page.</a></p>
<p>Feel free to check it out and complete next steps. I've separated iterations in different branches so you can compare it with your own implementation.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>So, after diving into Test-Driven Development (TDD) and exploring its ins and outs, I've got to say, it's a game-changer! </p>
<p>Let me break it down for you:</p>
<p>Key Points:</p>
<ul>
<li>TDD is all about writing tests before writing the actual code. It might sound a bit weird at first, but trust me, it works wonders.</li>
<li>The TDD process follows a simple cycle: write failing tests, implement the code to make those tests pass, and then refactor as needed to keep everything running smoothly.</li>
<li>By emphasising automated tests, TDD helps us design and develop software that's solid, maintainable, and adaptable over time.</li>
</ul>
<p>We started by creating test classes and writing empty test functions but it's your task now to finish it (Or you can jump to the shared repo right away :) ). </p>
<p>It might seem a bit odd to have tests that don't do anything, but it's all part of the plan.</p>
<p>Next, we laid out a clear plan of what our feature should do, based on a data flow chart. This helped us understand the requirements before diving into the implementation.</p>
<p>With the plan in hand, we began implementing the necessary components (ViewModel in this case), making sure our tests failed first. That's right, failing tests are actually a good thing in TDD!</p>
<p>Gradually, we connected pieces together, like setting up the <code>UserAutoScrollSettingsUseCase</code> class to handle font size calculation based on the auto-scroll speed (Check project repo).</p>
<p>We  also tackled UI components, allowing users to input their desired scroll speed, and making sure the font size was adjusted accordingly (Check project repo).</p>
<p>Throughout the process, we made sure to keep our code clean and simple, focusing on what was needed to make the tests pass. No unnecessary complexity here!</p>
<p>By the end, we had our "Font Size Auto Setting" feature up and running, with tests that passed with flying colours.</p>
<p>Remember, TDD isn't about rushing through tests or coding like crazy. It's about being deliberate and thoughtful in your development process, which pays off big time in the long run.</p>
<p>So, if you're looking to level up your software development game, give TDD a shot! It's a powerful approach that will make your code more solid, reduce bugs, and make you a better developer overall.</p>
<p>What I've shared is, how we work in my team and it's working for us, but it's not the perfect solution for every team/company. You need to find out whether it's yours or not. Let me know if you think I can improve this solution.</p>
<p>Happy coding! 🚀</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Do Test-Driven Development with Svelte and Vitest – A Project-Based Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ By Sriram Thiagarajan Test Driven Development (TDD) is one of the best ways to make sure your code is high quality and works like it's supposed to work. It can also help you create reliable builds during continuous deployments.  In this post, we will... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-do-test-driven-development-with-svelte-and-vitest/</link>
                <guid isPermaLink="false">66d461492472e5ed2fa07bbd</guid>
                
                    <category>
                        <![CDATA[ Svelte ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ test driven development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vite ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 19 Sep 2022 17:20:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/SvelteVitestTDDPoster.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sriram Thiagarajan</p>
<p>Test Driven Development (TDD) is one of the best ways to make sure your code is high quality and works like it's supposed to work. It can also help you create reliable builds during continuous deployments. </p>
<p>In this post, we will learn how to create a Svelte application using TDD methods.</p>
<h2 id="heading-what-were-building">What We're Building</h2>
<p>We are going to build a vertical tabs component where we can switch between three tabs. We are going to build this component by writing test cases first and developing the component functionality after that to make the tests more effective.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/FinalComponent-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Final implementation</em></p>
<h2 id="heading-prerequisite">Prerequisite</h2>
<p>I will explain all the steps needed to create an app and you can follow along with the code. It's great if you have basic programming knowledge and fundamental knowledge of HTML and CSS for this tutorial.</p>
<p>Also, you'll need to have Node.js installed. You can <a target="_blank" href="https://nodejs.org/en/">see how to do that here</a> if you don't have it already.</p>
<h2 id="heading-what-is-test-driven-development">What is Test-Driven Development?</h2>
<p>The basic idea of test-driven development, or TDD, is to write the test before you implement the actual functionality. This helps you clearly figure out what you're developing and how it works. </p>
<p>You first watch the test fail, and then you write the code to make it pass. This ensures that there are no false positive tests in your code.</p>
<p>TDD is a methodology you can apply to any programming language. It is more prevalent when developing backend applications that contain business logic that you can easily test. </p>
<p>The good news is, you can apply similar techniques to test your front-end applications as well.</p>
<h2 id="heading-three-stages-of-tdd">Three stages of TDD</h2>
<p>The three stages of TDD are:</p>
<ol>
<li>Red stage – Write the test and watch it fail</li>
<li>Green stage – Write the minimum code required to make the test pass</li>
<li>Refactor – Cleanup and refactor the code to make it more robust</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/TDDStages.png" alt="Image" width="600" height="400" loading="lazy">
<em>Three stages of TDD</em></p>
<h2 id="heading-what-is-vitest">What is Vitest?</h2>
<p>Vitest is an up-and-coming testing framework which has similar functionality to Jest. </p>
<p>Since we are using Vite as our build tool for Svelte in this tutorial, Vitest has very good integration with Vite and offers a similar testing environment without needing extra configuration.</p>
<h2 id="heading-how-to-create-a-svelte-application">How to Create a Svelte Application</h2>
<p>We are going to create a Svelte application using Vite as the build tool. You can do that with this command:</p>
<pre><code>npm create vite@latest
</code></pre><p>This will create a new project, and you can follow the steps below to create and setup the project:</p>
<ol>
<li>Enter the name of the project. This will also create a new folder with the project name. In this example, I will add the project name as <code>svelte-tdd-vitest</code>.</li>
<li>You can select the framework in the next step. Let's choose <code>svelte</code> as the framework.</li>
<li>Then you can enter the variant of the framework. We can choose the <code>TypeScript</code> variant for this article. If you are not comfortable with TypeScript, you can also choose <code>JavaScript</code> in this option.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ProjectInit.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initialise Svelte project with Vite</em></p>
<p>You can then follow the helpful steps provided in the terminal to install the dependencies and start the application. Run the following command:</p>
<pre><code>cd svelte-tdd-vitest
npm install
npm run dev
</code></pre><p><code>npm install</code> will install the dependencies of the project. </p>
<p><code>npm run dev</code> will start the development server. You should see the app running in the port specified in the terminal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ViteServerStartCmd.png" alt="Image" width="600" height="400" loading="lazy">
<em>Vite Server started using npm run dev</em></p>
<p>Congrats, you can now see the starter app running in your browser. You can open the project in your favourite Code Editor and start working.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/SvelteViteStarter.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-set-up-vitest">How to Set Up Vitest</h2>
<p>You can add Vitest to the project right now as a dev dependency. This means that Vitest will not be packaged into the production build of the application since you will be running the test in your local environment.</p>
<pre><code>npm install -D vitest
</code></pre><p>Vitest can read the config of Vite inside the <code>vite.config.js</code> file and prepare the test environment similar to the build environment. This makes the test more reliable. So you can reuse the Vite config file and add more options for the configuration of Vitest.</p>
<p>You can also override the config for the Vitest by creating a new file called <code>vitest.config.js</code> in the project root. So now, create a new file called <code>vitest.config.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vitest/config'</span>
<span class="hljs-keyword">import</span> { svelte } <span class="hljs-keyword">from</span> <span class="hljs-string">'@sveltejs/vite-plugin-svelte'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [
    svelte({ <span class="hljs-attr">hot</span>: !process.env.VITEST }),
  ],
  <span class="hljs-attr">test</span>: {
    <span class="hljs-attr">environment</span>: <span class="hljs-string">'jsdom'</span>,
  }
})
</code></pre>
<p>There are a couple of configs we are adding to the file</p>
<ol>
<li>We are disabling Svelte's hot module reload when tests are running. </li>
<li>We are defining the environment for running the test as <code>jsdom</code>. It helps in mocking the DOM API and running the tests in a reliable method.</li>
</ol>
<p>In order to use the <code>jsdom</code> you need to add it as an Dev Dependency as well. So let's install that package using the terminal.</p>
<pre><code>npm install -D jsdom
</code></pre><p>After installation, let's add a couple of scripts to the <code>package.json</code> file to start the Vitest test from the <code>npm</code> command line:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    ...
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"vitest"</span>,
        <span class="hljs-attr">"coverage"</span>: <span class="hljs-string">"vitest run --coverage"</span>
}
</code></pre>
<h2 id="heading-how-to-create-the-first-test">How to Create the First Test</h2>
<p>You now have all the setup needed to write your first test. Create a new file called <code>sample.spec.ts</code> inside the <code>lib</code> directory.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {describe, test, expect } <span class="hljs-keyword">from</span> <span class="hljs-string">'vitest'</span>;

describe(<span class="hljs-string">"Example File"</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">"Sample test"</span>, <span class="hljs-function">() =&gt;</span> {
        expect(<span class="hljs-number">1</span> + <span class="hljs-number">3</span>).equal(<span class="hljs-number">4</span>);
    });
});
</code></pre>
<p>Let's break down the different functions used to create this test file:</p>
<ol>
<li><code>describe</code> – you use this to group similar test together and benchmark tests when generating your reports. It takes a name and a function that contains the group of tests.</li>
<li><code>test</code> – Represents a single test. It can contain multiple expectations within it. It is created by passing a name of the test and the function to run the test.</li>
<li><code>expect</code> – Represents the expression which you're testing.</li>
</ol>
<p>There are multiple different ways to write your test based on what you are testing. You can have a look at the complete API for Vitest in the <a target="_blank" href="https://vitest.dev/api/">official API Reference</a>.</p>
<p>Let's run the test using the following npm command:</p>
<pre><code>npm run test
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2022/09/NpmRunFirstTest.png" alt="Image" width="600" height="400" loading="lazy">
<em>Running the test</em></p>
<h2 id="heading-how-to-add-the-global-test-config">How to Add the Global Test Config</h2>
<p>You are going to be using the <code>describe</code>, <code>test</code>, and <code>expect</code> functions a lot in the test files and it might be verbose to import them in all the test files. So Vitest has a nice config where you can set these global imports and so you don't have to add them to each file. </p>
<p>So let's update the <code>vitest.config.js</code> file with this configuration:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  ...
  test: {
    ...
    globals: <span class="hljs-literal">true</span>
  }
})
</code></pre>
<p>After adding this <code>globals</code> equals true line in your config, you can now remove the imports in your spec file. </p>
<p>If you are using TypeScript, your TypeScript compiler will complain in your spec file. You can solve that by adding the following line to your <code>tsconfig.json</code> file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"extends"</span>: <span class="hljs-string">"@tsconfig/svelte/tsconfig.json"</span>,
  <span class="hljs-attr">"compilerOptions"</span>: {
    ...
    <span class="hljs-attr">"types"</span>: [<span class="hljs-string">"vitest/globals"</span>]
  },
}
</code></pre>
<p>Now your test can look like this. This is not a huge upgrade for this small file, but when you have lots of spec files, this config change is useful.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"Example File"</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">"Sample test"</span>, <span class="hljs-function">() =&gt;</span> {
        expect(<span class="hljs-number">1</span> + <span class="hljs-number">3</span>).equal(<span class="hljs-number">4</span>);
    });
});
</code></pre>
<h2 id="heading-how-to-create-a-svelte-component">How to Create a Svelte Component</h2>
<p>We will create a new svelte component called <code>VerticalTabs.svelte</code>. The requirements are to create a vertical tab component that can contain a few items and for the user to be able to select a particular tab to view its content in the right side.</p>
<p>The component will be divided into two parts. The left side displays all the tabs. The right side displays the content based on the tab.</p>
<p>Let's create the basic HTML and CSS styles needed for the component. We will add the functionality to switch tabs after writing the tests.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>First Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Second Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Third Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-content"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>First Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem aut deserunt veniam tempora deleniti quos reprehenderit natus. Animi, obcaecati dolorum, culpa, maiores maxime ullam soluta unde rerum nihil temporibus quibusdam!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-class">.vertical-tab-container</span> {
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-direction</span>: row;
        <span class="hljs-attribute">align-items</span>: center;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid gray;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
    }

    <span class="hljs-selector-class">.vertical-tab</span> {
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">0px</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">3rem</span>;
        <span class="hljs-attribute">list-style</span>: none;
        <span class="hljs-attribute">border-right</span>: <span class="hljs-number">1px</span> solid gray
    }

    <span class="hljs-selector-class">.vertical-tab</span> <span class="hljs-selector-tag">li</span> {
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-selector-class">.vertical-tab-content</span> {
        <span class="hljs-attribute">flex</span>:<span class="hljs-number">1</span>
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>In this code, you are adding simple elements like an unordered list to display the list of tabs. You are styling it in the <code>&lt;style&gt;</code> tag which will be locally scoped CSS for this component.</p>
<p>Then, you are adding <code>&lt;h2&gt;</code> tag to display the tab heading and a paragraph tag <code>&lt;p&gt;</code> to show more dummy text for the tab. You're using <code>flex</code> to show the two items side by side and the property of <code>flex: 1</code> on the content will make that container take all the remaining available space to expand.</p>
<p>The component should look like the below image:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/VerticalTabInitial-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Vertical Tab initial</em></p>
<h2 id="heading-how-to-mount-the-svelte-component-in-test">How to Mount the Svelte Component in Test</h2>
<p>Now you need to create the first test for the component by mounting the svelte component and then checking to see if you can find the "First Tab" text in the component. </p>
<p>So create a new spec file called <code>VerticalTabs.spec.ts</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> VerticalTabs <span class="hljs-keyword">from</span> <span class="hljs-string">"./VerticalTabs.svelte"</span>;

describe(<span class="hljs-string">"VerticalTabs Component"</span>, <span class="hljs-function">() =&gt;</span> {

    test(<span class="hljs-string">"should render the component"</span>, <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-comment">// Create a new container for the test</span>
        <span class="hljs-keyword">const</span> host = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'div'</span>);

        <span class="hljs-comment">// Append the new container in the HTML body</span>
        <span class="hljs-built_in">document</span>.body.appendChild(host);

        <span class="hljs-comment">// Create an instance of the vertical tab</span>
        <span class="hljs-keyword">const</span> instance = <span class="hljs-keyword">new</span> VerticalTabs({ <span class="hljs-attr">target</span>: host });

        <span class="hljs-comment">// Check if the instance has value</span>
        expect(instance).toBeTruthy()

        <span class="hljs-comment">// Test if we can find the "First Tab Heading"</span>
        expect(host.innerHTML).toContain(<span class="hljs-string">"First Tab Heading"</span>)

    });

})
</code></pre>
<p>In order to mount the Svelte component, you need to first create a <code>div</code> container and attach that <code>div</code> to the <code>body</code> of the HTML document. Then you need to attach your component to the <code>div</code>. You can then test the <code>innerHTML</code> of the main container to see if you have the required content.</p>
<p>Now this test should pass since you have the <code>First Tab Heading</code> content displayed in the component.</p>
<p>Going through this long process in all the steps might prove to be difficult. So let's add another package to make the job easier. The package is <code>testing-library/svelte</code> and it provides more features to make the assertions easy and less verbose.</p>
<h2 id="heading-how-to-use-the-svelte-testing-library">How to Use the Svelte Testing Library</h2>
<p>First, you'll need to install the library:</p>
<pre><code>npm install -D @testing-library/svelte
</code></pre><p>Let's update the previous test to make it less verbose and let <code>testing-library</code> handle all the heavy lifting for us. You can use the <code>render</code> function to add the component to the testing page.</p>
<pre><code><span class="hljs-keyword">import</span> VerticalTabs <span class="hljs-keyword">from</span> <span class="hljs-string">"./VerticalTabs.svelte"</span>;
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/svelte'</span>;

describe(<span class="hljs-string">"VerticalTabs Component"</span>, <span class="hljs-function">() =&gt;</span> {

    test(<span class="hljs-string">"should render the component"</span>, <span class="hljs-function">() =&gt;</span> {

        render(VerticalTabs);

        <span class="hljs-keyword">const</span> firstTabNode = screen.getByText(<span class="hljs-regexp">/First Tab Heading/i</span>)

        expect(firstTabNode).toBeTruthy()
    });

})
</code></pre><p>After the <code>render</code> function, add the component to the testing page. You can use the <code>screen</code> object imported from the library to query the nodes that are rendered.</p>
<p>There are multiple methods inside this object to make testing easy, and you will use one of the methods to get the text in the component.</p>
<p><code>getByText</code> will return the instance of a given text. You are expecting the node to contain some value.</p>
<p>There are three main ways to retrieve the element in the testing library, and each serves a different purpose:</p>
<ol>
<li>getByText – This will throw an error when the text is not found and the test will fail</li>
<li>queryByText – This will return null when the text is not found</li>
<li>findByText – This will also throw an error when the text is not found and you can use it when doing async tests where the element will take some time to appear/disappear</li>
</ol>
<p>You can find a useful summary of these helper functions in the <a target="_blank" href="https://testing-library.com/docs/queries/about">official docs page</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/QueriesSummary.png" alt="Image" width="600" height="400" loading="lazy">
<em>Summary screenshot from Official docs of testing library</em></p>
<p>You can find more details on this API in this <a target="_blank" href="https://testing-library.com/docs/svelte-testing-library/api">official page</a>.</p>
<h2 id="heading-how-to-build-the-tab-switching-feature">How to Build the Tab Switching Feature</h2>
<p>We will start adding the feature to switch tabs in the component and test the component by writing the test first.</p>
<h3 id="heading-red-stage">Red stage</h3>
<p>Let's write a test the switch to a different tab on click of the "Second Tab" list item. </p>
<p>Since we don't have this functionality implemented, we will fail this test first and that's okay. Once we fail the test, we should write the logic to make it pass in the next step. </p>
<p>So let's write a failing test:</p>
<pre><code>test(<span class="hljs-string">"should switch tabs"</span>, <span class="hljs-keyword">async</span> () =&gt; {
        render(VerticalTabs);

        <span class="hljs-keyword">const</span> secondTabElement = screen.getByText(<span class="hljs-regexp">/Second Tab/i</span>);

        fireEvent.click(secondTabElement)

        <span class="hljs-keyword">await</span> screen.findByText(<span class="hljs-regexp">/Second Tab Heading/i</span>);
})
</code></pre><p>We are using the <code>fireEvent</code> from the testing library to simulate the click of the element. We can make the test <code>async</code> and <code>await</code> for the element since the text will change after the element is clicked.</p>
<p>You should have a failing test now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/TestFailing.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test failing unable to find the content</em></p>
<h3 id="heading-green-stage">Green stage</h3>
<p>Let's add the logic to change the tab in the Svelte component. We can do that easily by creating a <code>selectedIndex</code> variable and changing its value based on the selected tab.</p>
<pre><code>&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">let</span> selectedIndex = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">const</span> changeSecondTab = <span class="hljs-function">() =&gt;</span> {
        selectedIndex = <span class="hljs-number">1</span>;
    }
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>First Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> changeSecondTab()}&gt;Second Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Third Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-content"</span>&gt;</span>
        {#if selectedIndex == 0}
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>First Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {:else if selectedIndex == 1}
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Second Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {/if}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre><p><strong>Note: This is not the best implementation.</strong> It is only meant for showing that you can do minimal work to make the test pass. We will clean it up in the next stage</p>
<p>We have a method <code>changeSecondTab</code> that will change the <code>selectedIndex</code> value to 1 which will make the <code>#if</code> condition to change the tab. Even though it is not the best solution to handle all cases, we have a starting point.</p>
<p>Let's look at the test now. It should be working:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/TestPassed.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-refactor">Refactor</h3>
<p>Let's fix the implementation to make it more generic and have it work for all three tabs. We can also add an indicator to show which tab is currently selected.</p>
<pre><code class="lang-javascript">&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">let</span> selectedIndex = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">const</span> changeTab = <span class="hljs-function">(<span class="hljs-params">index: number</span>) =&gt;</span> {
        selectedIndex = index;
    }
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class:selected</span>=<span class="hljs-string">{selectedIndex</span> == <span class="hljs-string">0}</span> 
            <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> changeTab(0)}&gt;First Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class:selected</span>=<span class="hljs-string">{selectedIndex</span> == <span class="hljs-string">1}</span> 
            <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> changeTab(1)}&gt;Second Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class:selected</span>=<span class="hljs-string">{selectedIndex</span> == <span class="hljs-string">2}</span> 
            <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> changeTab(2)}&gt;Third Tab<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-content"</span>&gt;</span>
        {#if selectedIndex == 0}
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>First Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {:else if selectedIndex == 1}
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Second Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {:else}
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Third Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {/if}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    ...
    <span class="hljs-selector-class">.selected</span> {
        <span class="hljs-attribute">color</span>: blue;
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>We have created a method <code>changeTab</code> that will be called on the click of each element and then change the <code>selectedIndex</code>. This will cause the <code>#if</code> logic to change the tab based on its value.</p>
<p>We also have <code>class:selected</code> followed by an expression and when the expression becomes true, the <code>selected</code> class is added to the element. So we have added one more CSS class and we made the text colour blue to show the selected tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/FinalComponent.png" alt="Image" width="600" height="400" loading="lazy">
<em>Finished vertical tabs component</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-375.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test after finishing refactor</em></p>
<p>We have now confirmed that the test is also passing after the refactor. You can continue this process to add more tests and features to your component.</p>
<h2 id="heading-how-to-add-animation">How to Add Animation</h2>
<p>Svelte makes it easy to add animation when content is changed. You can make use of the <code>transition</code> directive to add pre-built animation to your application.</p>
<p>So let's add a fly animation when the content changes. You can import the fly animation from <code>svelte/transition</code> and then add it to the element using <code>transition:fly</code>. This will add the default fly animation when the content flies out and new content flies in. Such a neat effect with just a single line of code!</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { fly } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte/transition'</span>;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vertical-tab-content"</span> &gt;</span>
        {#if selectedIndex == 0}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">transition:fly</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>First Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {:else if selectedIndex == 1}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">transition:fly</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Second Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {:else}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">transition:fly</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Third Tab Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {/if}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>Animation brings life to your application and helps it stand out. I am a big fan of the simple animation transition system in Svelte.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you have learned how to create a new component using test-driven development methodology. Please share your feedback on this post and let me know your thoughts.</p>
<p>Thanks for reading! You can contact me on Twitter <a target="_blank" href="https://twitter.com/sriram_thiagar">@sriram_thiagar</a>. I regularly post articles on my blog <a target="_blank" href="https://www.eternaldev.com/">eternaldev.com</a> if you want to read more articles from me.</p>
<p>Hello everyone. I am Sriram, and I work as a Full Stack developer. I like to share my learning with others. I have been <a target="_blank" href="https://www.eternaldev.com/">blogging</a> for more than a year now on my website.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An introduction to test-driven development with Vue.js ]]>
                </title>
                <description>
                    <![CDATA[ By Sarah Dayan Test-driven development (TDD) is a process where you write tests before you write the associated code. You first write a test that describes an expected behavior, and you run it, ensuring it fails. Then, you write the dumbest, most str... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/an-introduction-to-tdd-with-vue-js-66544710b50c/</link>
                <guid isPermaLink="false">66c3445f0fa3812cdd5ea99b</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 17 May 2019 15:45:21 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*QphJEMJgj30s60_w" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sarah Dayan</p>
<p>Test-driven development (TDD) is a process where <strong>you write tests before you write the associated code</strong>. You first write a test that describes an expected behavior, and you run it, ensuring it fails. Then, you write the dumbest, most straightforward code you can to make the test pass. Finally, you refactor the code to make it right. And you repeat all the steps for each test until you’re done.</p>
<p>This approach has many advantages. First, <strong>it forces you to think before you code</strong>. It’s commonplace to rush into writing code before establishing what it should do. This practice leads to wasting time and writing complicated code. With TDD, any new piece of code requires a test first, so you have no choice but take the time to define what this code should do before you write it.</p>
<p>Secondly, <strong>it ensures you write unit tests</strong>. Starting with the code often leads to writing incomplete tests, or even no tests at all. Such a practice usually happens as a result of not having precise and exhaustive specs, which leads to spending more time coding than you should. Writing tests becomes a costly effort, which is easy to undermine once the production code is ready.</p>
<p><strong>Unit tests are critical to building robust code</strong>. Overlooking or rushing them increases chances of your code breaking in production at some point.</p>
<h3 id="heading-why-do-tdd-for-components">Why do TDD for components?</h3>
<p><strong>Testing a component can be counter-intuitive</strong>. As we saw in <a target="_blank" href="https://frontstuff.io/unit-test-your-first-vuejs-component">Unit Test Your First Vue.js Component</a>, it requires a mental shift to wrap your head around testing components versus testing plain scripts, knowing what to test, and understanding the line between unit tests and end-to-end.</p>
<p><strong>TDD makes all this easier</strong>. Instead of writing tests by examining all bits and pieces of a finished project and trying to guess what you should cover, you’re doing the opposite. You’re starting from actual specs, a list of things that the component should <em>do</em>, without caring about how it does it. This way, you’re ensuring that all you test is the public API, but you’re also guaranteeing you don’t forget anything.</p>
<p>In this tutorial, we’ll build <strong>a color picker</strong>. For every swatch, users can access the matching color code, either in hexadecimal, RGB, or HSL.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Wrkahf5Etl-FNZ1wqzdKG4dK9lnJtfmjL6Nt" alt="Image" width="706" height="450" loading="lazy">
_Design inspired from [Chris Castillo](https://dribbble.com/shots/2908891-Custom-Color-Picker-Exploration" rel="noopener" target="_blank" title=""&gt;Custom Color Picker Exploration by &lt;a href="https://dribbble.com/_ChrisCastillo" rel="noopener" target="<em>blank" title=")</em></p>
<p>Despite its apparent simplicity, there are a bunch of small pieces of logic to test. They require some thinking before jumping into code.</p>
<p>In this article, we’ll deep dive into TDD. We’ll <a target="_blank" href="https://frontstuff.io/an-introduction-to-tdd-with-vuejs#write-down-your-specs">put some specs together</a> before we write a single line of code. Then, we’ll <a target="_blank" href="https://frontstuff.io/an-introduction-to-tdd-with-vuejs#write-test-driven-code">test every public feature</a> in a test-driven fashion. Finally, we’ll reflect on what we did and <a target="_blank" href="https://frontstuff.io/an-introduction-to-tdd-with-vuejs#afterthoughts">see what we can learn from it</a>.</p>
<h3 id="heading-before-we-start">Before we start</h3>
<p>This tutorial assumes you’ve already built something with Vue.js before, and written unit tests for it using <a target="_blank" href="https://vue-test-utils.vuejs.org/">Vue Test Utils</a> and <a target="_blank" href="https://jestjs.io/">Jest</a> (or a similar test runner). It won’t go deeper into the fundamentals, so make sure you get up to speed first. If you’re not there yet, I recommend you go over <a target="_blank" href="https://frontstuff.io/build-your-first-vue-js-component">Build Your First Vue.js Component</a> and <a target="_blank" href="https://frontstuff.io/unit-test-your-first-vuejs-component">Unit Test Your First Vue.js Component</a>.</p>
<p><strong><em>TL;DR:</em></strong> <em>this post goes in-depth in the how and why. It’s designed to help you understand every decision behind testing a real-world Vue.js component with TDD and teach you how to make design decisions for your future projects. If you want to understand the whole thought process, read on. Otherwise, you can go directly to the <a target="_blank" href="https://frontstuff.io/an-introduction-to-tdd-with-vuejs#afterthoughts">afterthoughts</a> at the end, or look at the final code on <a target="_blank" href="https://github.com/sarahdayan/colorpicker-tdd-tutorial">GitHub</a>.</em></p>
<h3 id="heading-write-down-your-specs">Write down your specs</h3>
<p>Before you even write your first test, <strong>you should write down an overview of what the component should do</strong>. Having specs makes testing much more straightforward since you’re mostly rewriting each spec in the form of tests.</p>
<p>Let’s think about the different parts that compose our component, and what they should do.</p>
<p>First, we have a collection of <strong>color swatches</strong>. We want to be able to pass a list of custom colors and display as swatches in the component. The first one should be selected by default, and the end user can select a new one by clicking it.</p>
<p>Secondly, we have the <strong>color mode toggler</strong>. The end user should be able to switch between three modes: hexadecimal (default), RGB and HSL.</p>
<p>Finally, we have the <strong>color code output</strong>, where the end user can get the code for the currently selected color swatch. This code is a combination of the selected swatch and color mode. Thus, by default, it should display the first swatch as a hexadecimal value. When changing any of these, the code should update accordingly.</p>
<p>As you can see, we don’t go too deep into details; we don’t specify what the color mode labels should be, or what the active state looks like for the color swatches. We can make most of the small decisions on the fly, even when doing TDD. Yet, we’ve come <strong>from a simple definition of what the component should be, to a comprehensive set of specs to start from</strong>.</p>
<h3 id="heading-write-test-driven-code">Write test-driven code</h3>
<p>First, you need to create a new Vue project with <a target="_blank" href="https://cli.vuejs.org/">Vue CLI</a>. You can check <a target="_blank" href="https://frontstuff.io/build-your-first-vue-js-component">Build Your First Vue.js Component</a> if you need a step by step guide.</p>
<p>During the scaffolding process, manually select features and make sure you check <strong>Unit testing</strong>. Pick Jest as your testing solution, and proceed until the project is created, dependencies are installed, and you’re ready to go.</p>
<p>We’ll need to use SVG files as components, so you also need to install the right loader for them. Install <a target="_blank" href="https://www.npmjs.com/package/vue-svg-loader">vue-svg-loader</a> as a dev dependency, and add a rule for it in your <code>vue.config.js</code> file.</p>
<pre><code><span class="hljs-comment">// vue.config.js</span>

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">chainWebpack</span>: <span class="hljs-function"><span class="hljs-params">config</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> svgRule = config.module.rule(<span class="hljs-string">'svg'</span>)
    svgRule.uses.clear()
    svgRule.use(<span class="hljs-string">'vue-svg-loader'</span>).loader(<span class="hljs-string">'vue-svg-loader'</span>)
  }
}
</code></pre><p>This loader doesn’t play well with Jest by default, which causes tests to throw. To fix it, create a <code>svgTransform.js</code> file <a target="_blank" href="https://vue-svg-loader.js.org/faq.html#how-to-use-this-loader-with-jest">as documented on the website</a>, and edit your <code>jest.config.js</code> as follows:</p>
<pre><code><span class="hljs-comment">// svgTransform.js</span>

<span class="hljs-keyword">const</span> vueJest = <span class="hljs-built_in">require</span>(<span class="hljs-string">'vue-jest/lib/template-compiler'</span>)

<span class="hljs-built_in">module</span>.exports = {
  process(content) {
    <span class="hljs-keyword">const</span> { render } = vueJest({
      content,
      <span class="hljs-attr">attrs</span>: {
        <span class="hljs-attr">functional</span>: <span class="hljs-literal">false</span>
      }
    })

    <span class="hljs-keyword">return</span> <span class="hljs-string">`module.exports = { render: <span class="hljs-subst">${render}</span> }`</span>
  }
}

<span class="hljs-comment">// jest.config.js</span>

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">transform</span>: {
    <span class="hljs-comment">// ...</span>
    <span class="hljs-string">'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$'</span>: <span class="hljs-string">'jest-transform-stub'</span>,
    <span class="hljs-string">'^.+\\.svg$'</span>: <span class="hljs-string">'&lt;rootDir&gt;/svgTransform.js'</span>
  },
  <span class="hljs-comment">// ...</span>
}
</code></pre><p>Note that we’ve removed “svg” from the first regular expression (the one that gets transformed with <code>jest-transform-stub</code>). This way, we ensure SVGs get picked up by <code>svgTransform.js</code>.</p>
<p>Additionally, you need to install <a target="_blank" href="https://www.npmjs.com/package/color-convert">color-convert</a> as a dependency. We’ll need it both in our code and in our tests later on.</p>
<p><strong>Don’t serve the project yet</strong>. We’re going to write tests and rely on them passing or not to move on. We don’t want to control whether what we build works by testing it visually in the browser, nor being distracted by how it looks.</p>
<p>Instead, open your project and create a new <code>ColorPicker.vue</code> single-file component in the <code>src/components/</code> directory. In <code>tests/unit/</code>, create its associated spec file.</p>
<pre><code>&lt;!-- ColorPicker.vue --&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>

<span class="hljs-comment">// ColorPicker.spec.js</span>

<span class="hljs-keyword">import</span> { shallowMount } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vue/test-utils'</span>
<span class="hljs-keyword">import</span> ColorPicker <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ColorPicker'</span>

describe(<span class="hljs-string">'ColorPicker'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// let's do this!</span>
})
</code></pre><p>In your terminal, execute the following command to run tests:</p>
<pre><code>npm run test:unit --watchAll
</code></pre><p>For now, you should get an error because you don’t yet have tests. Don’t worry though; we’ll fix this shortly ? Note the usage of the -<code>-watchAll</code> flag in the command: Jest is now watching your files. This way, you won’t have to re-run test by hand.</p>
<p>TDD goes in 3 stages:</p>
<ol>
<li><strong>Red</strong>: you write a test that describes an expected behavior, then you run it, ensuring it fails.</li>
<li><strong>Green</strong>: you write the dumbest, most straightforward code you can to make the test pass.</li>
<li><strong>Refactor</strong>: you refactor the code to make it right.</li>
</ol>
<h3 id="heading-step-1-red">Step 1: Red</h3>
<p>Time to write our first test! We’ll start with the color swatches. For clarity, we’ll wrap all tests for each distinct element in their own suite, using a <code>describe</code> block.</p>
<p>First, we want to make sure that the component displays each color that we provide as an individual swatch. We would pass those as props, in the form of an array of hexadecimal strings. In the component, we would display the list as an unordered list, and assign the background color via a <code>style</code> attribute.</p>
<pre><code><span class="hljs-keyword">import</span> { shallowMount } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vue/test-utils'</span>
<span class="hljs-keyword">import</span> ColorPicker <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ColorPicker'</span>
<span class="hljs-keyword">import</span> convert <span class="hljs-keyword">from</span> <span class="hljs-string">'color-convert'</span>

<span class="hljs-keyword">let</span> wrapper = <span class="hljs-literal">null</span>

<span class="hljs-keyword">const</span> propsData = {
  <span class="hljs-attr">swatches</span>: [<span class="hljs-string">'e3342f'</span>, <span class="hljs-string">'3490dc'</span>, <span class="hljs-string">'f6993f'</span>, <span class="hljs-string">'38c172'</span>, <span class="hljs-string">'fff'</span>]
}

beforeEach(<span class="hljs-function">() =&gt;</span> (wrapper = shallowMount(ColorPicker, { propsData })))
afterEach(<span class="hljs-function">() =&gt;</span> wrapper.destroy())

describe(<span class="hljs-string">'ColorPicker'</span>, <span class="hljs-function">() =&gt;</span> {
  describe(<span class="hljs-string">'Swatches'</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">'displays each color as an individual swatch'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> swatches = wrapper.findAll(<span class="hljs-string">'.swatch'</span>)
      propsData.swatches.forEach(<span class="hljs-function">(<span class="hljs-params">swatch, index</span>) =&gt;</span> {
        expect(swatches.at(index).attributes().style).toBe(
          <span class="hljs-string">`background: rgb(<span class="hljs-subst">${convert.hex.rgb(swatch).join(<span class="hljs-string">', '</span>)}</span>)`</span>
        )
      })
    })
  })
})
</code></pre><p>We mounted our <code>ColorPicker</code> component and wrote a test that expects to find items with a background color matching the colors passed as props. <strong>This test is bound to fail</strong>: we currently have nothing in <code>ColorPicker.vue</code>. If you look at your terminal, you should have an error saying that no item exists at 0. This is great! <strong>We just passed the first step of TDD with flying colors.</strong></p>
<h3 id="heading-step-2-green">Step 2: Green</h3>
<p>Our test is failing; we’re on the right track. Now, time to make it pass. We’re not much interested in writing working or smart code at this point, all we want is to make Jest happy. Right now, Vue Test Utils complains about the fact that we don’t event have no item at index 0.</p>
<pre><code>[vue-test-utils]: no item exists at <span class="hljs-number">0</span>
</code></pre><p>The simplest thing we can do to make that error go away is to add an unordered list with a <code>swatch</code> class on the list item.</p>
<pre><code>&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-picker"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatches"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/template&gt;
</code></pre><p>Jest still complains but the error has changed:</p>
<pre><code>Expected value to equal:
  <span class="hljs-string">"background: rgb(227, 52, 47);"</span>
<span class="hljs-attr">Received</span>:
  <span class="hljs-literal">undefined</span>
</code></pre><p>This makes sense; the list item doesn’t have a <code>style</code> attribute. The simplest thing we can do about it is to hardcode the <code>style</code> attribute. This isn’t what we want in the end, but, we aren’t concerned about it yet. What we want is <strong>for our test to go green</strong>.</p>
<p>We can therefore hardcode five list items with the expected style attributes:</p>
<pre><code>&lt;ul <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"swatches"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background: rgb(227, 52, 47);"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background: rgb(52, 144, 220);"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background: rgb(246, 153, 63);"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background: rgb(56, 193, 114);"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background: rgb(255, 255, 255);"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
&lt;/ul&gt;
</code></pre><p>The test should now pass.</p>
<h3 id="heading-step-3-refactor">Step 3: Refactor</h3>
<p>At this stage, we want to rearrange our code to make it right, without breaking tests. In our case, we don’t want to keep the list items and their <code>style</code> attributes hardcoded. Instead, it would be better to receive swatches as a prop, iterate over them to generate the list items, and assign the colors as their background.</p>
<pre><code>&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-picker"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"swatches"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
        <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>
        <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(swatch, index) in swatches"</span>
        <span class="hljs-attr">:style</span>=<span class="hljs-string">"{ background: `#${swatch}` }"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span>
      &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/template&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">props</span>: {
    <span class="hljs-attr">swatches</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Array</span>,
      <span class="hljs-keyword">default</span>() {
        <span class="hljs-keyword">return</span> []
      }
    }
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre><p>When tests re-run, they should still pass ? This means w<strong>e’ve successfully refactored the code without affecting the output.</strong> Congratulations, you’ve just completed your first TDD cycle!</p>
<p>Now, before we go to the next test, let’s reflect a bit. You may be wondering:</p>
<blockquote>
<p>“Isn’t this a bit dumb? I knew the test would fail. Am I not wasting time by running it anyway, then hardcoding the right value, see the test pass, then make the code right? Can’t I go to the refactor step directly?”</p>
</blockquote>
<p>It’s understandable that you’re feeling confused by the process. Yet, try to look at things from a different angle: the point here isn’t to <em>prove</em> that the test doesn’t pass. We know it won’t. What we want to look at is what our test <em>expects</em>, make them happy in the simplest possible way, and finally write smarter code without breaking anything.</p>
<p>That’s the whole idea of test-driven development: we don’t write code to make things work, <strong>we write code to make tests pass</strong>. By reversing the relationship, we’re ensuring robust tests with a focus on the outcome.</p>
<h3 id="heading-what-are-we-testing">What are we testing?</h3>
<p>Another question that may come to mind is <strong>how we’re deciding what to test</strong>. In <a target="_blank" href="https://frontstuff.io/unit-test-your-first-vuejs-component">Unit Test Your First Vue.js Component</a>, we saw that we should only be testing the public API of our component, not the internal implementation. Strictly speaking, this means we should cover <strong>user interactions</strong> and <strong>props changes</strong>.</p>
<p>But is that all? For example, is it okay for the output HTML to break? Or for CSS class names to change? Are we sure nobody is relying on them? That you aren’t yourself?</p>
<p><strong>Tests should give you confidence that you aren’t shipping broken software.</strong> What people can do with your program shouldn’t stop working the way they expect it to work. It can mean different things depending on the project and use case.</p>
<p>For example, if you’re building this color panel as an open source component, your users are other developers who use it in their own projects. They’re likely relying on the class names you provide to style the component to their liking. <strong>The class names become a part of your public API because your users rely on them.</strong></p>
<p>In our case, we may not necessarily be making an open source component, but we have view logic that depends on specific class names. For instance, it’s important for active swatches to have an <code>active</code> class name, because we’ll rely on it to display a checkmark, in CSS. If someone changes this by accident, we want to know about it.</p>
<p>Testing scenarios for UI components highly depend on the use case and expectations. Whichever the case, what you need to ask yourself is <strong>do I care about this if it changes</strong>?</p>
<h3 id="heading-next-tests">Next tests</h3>
<h4 id="heading-testing-the-swatches">Testing the swatches</h4>
<p>Let’s move on to the next test. We expect the first swatch of the list to be the one that’s selected by default. From the outside, <strong>this is something that we want to ensure keeps on working the same way</strong>. Users could, for instance, rely on the active class name to style the component.</p>
<pre><code>test(<span class="hljs-string">'sets the first swatch as the selected one by default'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> firstSwatch = wrapper.find(<span class="hljs-string">'.swatch'</span>)
  expect(firstSwatch.classes()).toContain(<span class="hljs-string">'active'</span>)
})
</code></pre><p>This test, too, should fail, as list items currently don’t have any classes. We can easily make this pass by adding the class on the first list item.</p>
<pre><code>&lt;li
  :key=<span class="hljs-string">"index"</span>
  v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"(swatch, index) in swatches"</span>
  :style=<span class="hljs-string">"{ background: `#${swatch}` }"</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"swatch"</span>
  :<span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"{ 'active': index === 0 }"</span>
&gt;&lt;/li&gt;
</code></pre><p>The test now passes; however, we’ve hardcoded the logic into the template. We can refactor that by externalizing the index onto which the class applies. This way, we can change it later.</p>
<pre><code>&lt;template&gt;
  &lt;!-- ... --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(swatch, index) in swatches"</span>
    <span class="hljs-attr">:style</span>=<span class="hljs-string">"{ background: `#${swatch}` }"</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"swatch"</span>
    <span class="hljs-attr">:class</span>=<span class="hljs-string">"{ active: index === activeSwatch }"</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  &lt;!-- ... --&gt;
&lt;/template&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">activeSwatch</span>: <span class="hljs-number">0</span>
    }
  }
}
</code></pre><p>This naturally leads us to our third test. We want to change the active swatch whenever the end user clicks it.</p>
<pre><code>test(<span class="hljs-string">'makes the swatch active when clicked'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> targetSwatch = wrapper.findAll(<span class="hljs-string">'.swatch'</span>).at(<span class="hljs-number">2</span>)
  targetSwatch.trigger(<span class="hljs-string">'click'</span>)
  expect(targetSwatch.classes()).toContain(<span class="hljs-string">'active'</span>)
})
</code></pre><p>For now, nothing happens when we click a swatch. However, thanks to our previous refactor, we can make this test go green and even skip the refactor step.</p>
<pre><code>&lt;li
  :key=<span class="hljs-string">"index"</span>
  v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"(swatch, index) in swatches"</span>
  :style=<span class="hljs-string">"{ background: `#${swatch}` }"</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"swatch"</span>
  :<span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"{ active: index === activeSwatch }"</span>
  @click=<span class="hljs-string">"activeSwatch = index"</span>
&gt;&lt;/li&gt;
</code></pre><p>This code makes the test pass and doesn’t even need a refactor. <strong>This is a fortunate side-effect of doing TDD</strong>: sometimes, the process leads to either writing new tests that either don’t need refactors, or even that pass right away.</p>
<p>Active swatches should show a checkmark. We’ll add it now <strong>without writing a test</strong>: instead, we’ll control their visibility via CSS later. This is alright since we’ve already tested how the <code>active</code> class applies.</p>
<p>First, create a <code>checkmark.svg</code> file in <code>src/assets/</code>.</p>
<pre><code>&lt;svg viewBox=<span class="hljs-string">"0 0 448.8 448.8"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"142.8 323.9 35.7 216.8 0 252.5 142.8 395.3 448.8 89.3 413.1 53.6"</span>/&gt;</span></span>
&lt;/svg&gt;
</code></pre><p>Then, import it in the component.</p>
<pre><code><span class="hljs-keyword">import</span> CheckIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@/assets/check.svg'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">components</span>: { CheckIcon }
}
</code></pre><p>Finally, add it inside the list items.</p>
<pre><code>&lt;li ... &gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">check-icon</span> /&gt;</span></span>
&lt;/li&gt;
</code></pre><p>Good! We can now move on to the next element of our component: <strong>the color mode</strong>.</p>
<h4 id="heading-testing-the-color-mode">Testing the color mode</h4>
<p>Let’s now implement the color mode toggler. The end user should be able to switch between hexadecimal, RGB and HSL. We’re defining these modes internally, but we want to ensure they render correctly.</p>
<p>Instead of testing button labels, <strong>we’ll rely on class names</strong>. It makes our test more robust, as we can easily define a class name as part of our component’s contract. However, button labels should be able to change.</p>
<p>Now you may be tempted to check for these three specific modes, but that would make the test brittle. What if we change them? What if we add one, or remove one? That would still be the same logic, yet the test would fail, forcing us to go and edit it.</p>
<p>One solution could be to access the component’s data to iterate on the modes dynamically. Vue Test Utils lets us do that through the <a target="_blank" href="https://vue-test-utils.vuejs.org/api/wrapper/#properties">vm</a> property, but again, this tightly couples our test with the internal implementation of the modes. If tomorrow, we decided to change the way we define modes, the test would break.</p>
<p>Another solution is to keep going with black box testing and only expect the class name to match a given <em>pattern</em>. We don’t care that it’s <code>color-mode-hex</code>, <code>color-mode-hsl</code> or <code>color-mode-xyz</code>, as long as it looks like what we expect from the outside. Jest lets us do that with regular expression matchers.</p>
<pre><code><span class="hljs-comment">// ...</span>
describe(<span class="hljs-string">'Color model'</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">'displays each mode as an individual button'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> buttons = wrapper.findAll(<span class="hljs-string">'.color-mode'</span>)
    buttons.wrappers.forEach(<span class="hljs-function"><span class="hljs-params">button</span> =&gt;</span> {
      expect(button.classes()).toEqual(
        expect.arrayContaining([expect.stringMatching(<span class="hljs-regexp">/color-mode-\w{1,}/</span>)])
      )
    })
  })
})
</code></pre><p>Here, we’re expecting elements with a class that follows the pattern “color-mode-“ + any word character (in ECMAScript, any character within <code>[a-zA-Z_0-9]</code>). We could add or remove any mode we want, and the test would still be valid.</p>
<p>Naturally, right now, the test should fail, as there are no buttons with class <code>color-mode</code> yet. We can make it pass by hardcoding them in the component.</p>
<pre><code>&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"color-modes"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-mode color-mode-hex"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-mode color-mode-rgb"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-mode color-mode-hsl"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>We can now refactor this code by adding the modes as private data in our component and iterate over them.</p>
<pre><code>&lt;template&gt;
  &lt;!-- ... --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-modes"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
      <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>
      <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(mode, index) in colorModes"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"color-mode"</span>
      <span class="hljs-attr">:class</span>=<span class="hljs-string">"`color-mode-${mode}`"</span>
    &gt;</span>{{ mode }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  &lt;!-- ... --&gt;
&lt;/template&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">activeSwatch</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">colorModes</span>: [<span class="hljs-string">'hex'</span>, <span class="hljs-string">'rgb'</span>, <span class="hljs-string">'hsl'</span>]
    }
  }
}
</code></pre><p>Good! Let’s move on.</p>
<p>As with the swatches, we want the first mode to be set as active. We can copy the test we wrote and adapt it to this new use case.</p>
<pre><code>test(<span class="hljs-string">'sets the first mode as the selected one by default'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> firstButton = wrapper.find(<span class="hljs-string">'.color-mode'</span>)
  expect(firstButton.classes()).toContain(<span class="hljs-string">'active'</span>)
})
</code></pre><p>We can make this test pass by manually adding the class on the first list item.</p>
<pre><code>&lt;button
  :key=<span class="hljs-string">"index"</span>
  v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"(mode, index) in colorModes"</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"color-mode"</span>
  :<span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"[{ active: index === 0 }, `color-mode-${mode}`]"</span>
&gt;{{ mode }}&lt;/button&gt;
</code></pre><p>Finally, we can refactor by externalizing the index onto which the class applies.</p>
<pre><code>&lt;template&gt;
  &lt;!-- ... --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
    <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>
    <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(mode, index) in colorModes"</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"color-mode"</span>
    <span class="hljs-attr">:class</span>=<span class="hljs-string">"[{ active: index === activeMode }, `color-mode-${mode}`]"</span>
  &gt;</span>{{ mode }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  &lt;!-- ... --&gt;
&lt;/template&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">activeSwatch</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">activeMode</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">colorModes</span>: [<span class="hljs-string">'hex'</span>, <span class="hljs-string">'rgb'</span>, <span class="hljs-string">'hsl'</span>]
    }
  }
}
</code></pre><p>We need to change the active mode whenever the end user clicks the associated button, as with the swatches.</p>
<pre><code>test(<span class="hljs-string">'sets the color mode button as active when clicked'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> targetButton = wrapper.findAll(<span class="hljs-string">'.color-mode'</span>).at(<span class="hljs-number">2</span>)
  targetButton.trigger(<span class="hljs-string">'click'</span>)
  expect(targetButton.classes()).toContain(<span class="hljs-string">'active'</span>)
})
</code></pre><p>We can now add a <code>@click</code> directive as we did with the swatches, and make the test go green without having to refactor.</p>
<pre><code>&lt;button
  :key=<span class="hljs-string">"index"</span>
  v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"(mode, index) in colorModes"</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"color-mode"</span>
  :<span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"[{ active: index === activeMode }, `color-mode-${mode}`]"</span>
  @click=<span class="hljs-string">"activeMode = index"</span>
&gt;{{ mode }}&lt;/button&gt;
</code></pre><h4 id="heading-testing-the-color-code">Testing the color code</h4>
<p>Now that we’re done testing the swatches and color code, we can move on to the third and final element of our color picker: <strong>the color code</strong>. What we display in there is a combination of the other two: the selected swatch defines the color we should display, and the selected mode determines how to display it.</p>
<p>First, we want to make sure we initially display the default swatch in the default mode. We have the information to build this since we’ve implemented the swatches and the color mode.</p>
<p>Let’s start with a (failing) test.</p>
<pre><code>describe(<span class="hljs-string">'Color code'</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">'displays the default swatch in the default mode'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(wrapper.find(<span class="hljs-string">'.color-code'</span>).text()).toEqual(<span class="hljs-string">'#e3342f'</span>)
  })
})
</code></pre><p>Now, let’s make this pass by hardcoding the expected result in the component.</p>
<pre><code>&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"color-code"</span>&gt;#e3342f&lt;/div&gt;
</code></pre><p>Good! Time to refactor. We have a raw color in hexadecimal mode, and we’re willing to output it in hexadecimal format. The only difference between our input and output values is that we want to prepend the latter with a hash character. The easiest way of doing so with Vue is via a <code>computed</code> property.</p>
<pre><code>&lt;template&gt;
  &lt;!-- ... --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"color-code"</span>&gt;</span>{{ activeCode }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  &lt;!-- ... --&gt;
&lt;/template&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">computed</span>: {
    activeCode() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">`#<span class="hljs-subst">${<span class="hljs-built_in">this</span>.swatches[<span class="hljs-built_in">this</span>.activeSwatch]}</span>`</span>
    }
  }
}
</code></pre><p>This should keep the test green. However, there’s an issue with this computed property: it only works for hexadecimal values. It should keep on working when we change the color, but not when we change the mode. We can verify this with another test.</p>
<pre><code>test(<span class="hljs-string">'displays the code in the right mode when changing mode'</span>, <span class="hljs-function">() =&gt;</span> {
  wrapper.find(<span class="hljs-string">'.color-mode-hsl'</span>).trigger(<span class="hljs-string">'click'</span>)
  expect(wrapper.find(<span class="hljs-string">'.color-code'</span>).text()).toEqual(<span class="hljs-string">'2°, 76%, 54%'</span>)
})
</code></pre><p>Here, we’ve changed to HSL mode, but we’re still getting the hexadecimal output. We need to refactor our code so that our <code>activeCode</code> computed property is not only aware of the current color, but also the current color mode. One way we can achieve this is to create computed properties for each mode and proxy them through <code>activeCode</code> based on the selected mode.</p>
<p>First, we should simplify access to the current color and mode. Right now, we need to do an array lookup, which is repetitive and makes the code hard to read. We can use computed properties to wrap that logic.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">computed</span>: {
    <span class="hljs-comment">// ...</span>
    activeColorValue() {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.swatches[<span class="hljs-built_in">this</span>.activeSwatch]
    },
    activeModeValue() {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.colorModes[<span class="hljs-built_in">this</span>.activeMode]
    }
  }
}
</code></pre><p>As you can see, we’re not writing tests for these computed properties, as they aren’t part of our public API. We’ll use them later in our dedicated color mode computed properties, which themselves will be proxied in <code>activeCode</code>, which we’re testing in our “Color code” suite. <strong>All we care about is that the color code renders as expected</strong> so that the user can rely on them. How we get there are implementation details that we need to be able to change if need be.</p>
<p>We can now write our dedicated computed properties for each mode. We’ll map their name onto the ones in <code>colorModes</code>, so we can do an array lookup later in <code>activeCode</code> to return the right one.</p>
<p>For the hexadecimal output, we can externalize what we currently have in <code>activeCode</code> and refactor it using <code>activeColorValue</code>.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">computed</span>: {
    <span class="hljs-comment">// ...</span>
    hex() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">`#<span class="hljs-subst">${<span class="hljs-built_in">this</span>.activeColorValue}</span>`</span>
    }
  }
}
</code></pre><p>Now, let’s modify <code>activeCode</code> so it proxies the right computed property depending on the active mode.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">computed</span>: {
    <span class="hljs-comment">// ...</span>
    activeCode() {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>[<span class="hljs-built_in">this</span>.activeModeValue]
    }
  }
}
</code></pre><p>This still shouldn’t make our latest test pass, since we haven’t written a computed property for it. However, our test that checks if the default mode renders correctly is still passing, which is a good sign we’re on the right track.</p>
<p>We now want to write a computed property that returns the color output in HSL mode. For this, we’ll use <code>color-convert</code>, an npm package that lets us convert colors in many different modes. We’ve already been using it in our tests, so we don’t have to reinstall it.</p>
<pre><code><span class="hljs-keyword">import</span> convert <span class="hljs-keyword">from</span> <span class="hljs-string">'color-convert'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">computed</span>: {
    <span class="hljs-comment">// ...</span>
    hsl() {
      <span class="hljs-keyword">const</span> hslColor = convert.hex.hsl(<span class="hljs-built_in">this</span>.activeColorValue)
      <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${hslColor[<span class="hljs-number">0</span>]}</span>°, <span class="hljs-subst">${hslColor[<span class="hljs-number">1</span>]}</span>%, <span class="hljs-subst">${hslColor[<span class="hljs-number">2</span>]}</span>%`</span>
    }
  }
}
</code></pre><p>Great, our test passes! We can now finish this up adding the missing RGB mode.</p>
<p>Yet, as you can see, we’re currently not testing the output of our color computed properties in isolation, but through other tests. To make things cleaner, we could decouple that logic from the component, import it as a dependency, and test it separately. This has several benefits:</p>
<ul>
<li>it keeps the component from growing every time we want to add a color mode,</li>
<li>it keeps domains separated: the component focuses on its own view logic, and the color modes utility takes care of testing each mode exhaustively.</li>
</ul>
<p>First, create a new <code>color.js</code> file in the <code>src/utils/</code> directory, and a matching spec file in <code>tests/unit/</code>.</p>
<pre><code><span class="hljs-comment">// color.spec.js</span>

<span class="hljs-keyword">import</span> { rgb, hex, hsl } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/color'</span>

<span class="hljs-comment">// color.js</span>

<span class="hljs-keyword">import</span> convert <span class="hljs-keyword">from</span> <span class="hljs-string">'color-convert'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> rgb = <span class="hljs-function">() =&gt;</span> {}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hex = <span class="hljs-function">() =&gt;</span> {}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hsl = <span class="hljs-function">() =&gt;</span> {}
</code></pre><p>We can use TDD to test those three functions and make sure they always return the expected value. We can extract the logic we had in our Vue component for the last two, and write the RGB function from scratch.</p>
<p>For the sake of brevity, we’ll cover all three tests at once, but the process remains the same.</p>
<pre><code><span class="hljs-keyword">import</span> { rgb, hex, hsl } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/color'</span>

<span class="hljs-keyword">const</span> color = <span class="hljs-string">'e3342f'</span>

describe(<span class="hljs-string">'color'</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">'returns the color into RGB notation'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(rgb(color)).toBe(<span class="hljs-string">'227, 52, 47'</span>)
  })
  test(<span class="hljs-string">'returns the color into hexadecimal notation'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(hex(color)).toBe(<span class="hljs-string">'#e3342f'</span>)
  })
  test(<span class="hljs-string">'returns the color into HSL notation'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(hsl(color)).toBe(<span class="hljs-string">'2°, 76%, 54%'</span>)
  })
})
</code></pre><p>We now have three failing tests. The first thing we can do is to return hardcoded values to go green.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> rgb = <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'227, 52, 47'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hex = <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'#e3342f'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hsl = <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'2°, 76%, 54%'</span>
</code></pre><p>Now, we can start refactoring by migrating the code from our Vue component.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hex = <span class="hljs-function">() =&gt;</span> <span class="hljs-string">`#<span class="hljs-subst">${color}</span>`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hsl = <span class="hljs-function"><span class="hljs-params">color</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> hslColor = convert.hex.hsl(color)
  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${hslColor[<span class="hljs-number">0</span>]}</span>°, <span class="hljs-subst">${hslColor[<span class="hljs-number">1</span>]}</span>%, <span class="hljs-subst">${hslColor[<span class="hljs-number">2</span>]}</span>%`</span>
}
</code></pre><p>Finally, we can implement our <code>rgb</code> function.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> rgb = <span class="hljs-function"><span class="hljs-params">color</span> =&gt;</span> convert.hex.rgb(color).join(<span class="hljs-string">', '</span>)
</code></pre><p>All tests should stay green!</p>
<p>We can now use the <code>color</code> utilities in our Vue component and refactor it a bit. We no longer need to import <code>color-convert</code> in the component, nor do we need dedicated computed properties for each mode, or even for getting the active color and mode values. All we need to keep is <code>activeCode</code>, where we can store all the necessary logic.</p>
<p>This is a good example where doing black box testing helps us: we’ve been focusing on testing the public API; thus <strong>we can refactor the internals of our component without breaking the tests</strong>. Removing properties like <code>activeColorValue</code> or <code>hex</code> doesn’t matter, because we were never testing them directly.</p>
<pre><code><span class="hljs-comment">// ...</span>
<span class="hljs-keyword">import</span> { rgb, hex, hsl } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/color'</span>

<span class="hljs-keyword">const</span> modes = { rgb, hex, hsl }

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">computed</span>: {
    activeCode() {
      <span class="hljs-keyword">const</span> activeColor = <span class="hljs-built_in">this</span>.swatches[<span class="hljs-built_in">this</span>.activeSwatch]
      <span class="hljs-keyword">const</span> activeMode = <span class="hljs-built_in">this</span>.colorModes[<span class="hljs-built_in">this</span>.activeMode]
      <span class="hljs-keyword">return</span> modes[activeMode](activeColor)
    }
  }
}
</code></pre><p>We now have much terser code in our component, and better domain separation, while still respecting the component’s contract.</p>
<p>Finally, we can implement a missing test: the one that ensures the color code changes whenever we click a new swatch. This should already go green, but it’s still essential for us to write it, so we can know about it if it breaks.</p>
<pre><code>test(<span class="hljs-string">'displays the code in the right color when changing color'</span>, <span class="hljs-function">() =&gt;</span> {
  wrapper
    .findAll(<span class="hljs-string">'.swatch'</span>)
    .at(<span class="hljs-number">2</span>)
    .trigger(<span class="hljs-string">'click'</span>)
  expect(wrapper.find(<span class="hljs-string">'.color-code'</span>).text()).toEqual(<span class="hljs-string">'#f6993f'</span>)
})
</code></pre><p>And we’re done! We just built a fully functional Vue component using TDD, without relying on browser output, <strong>and our tests are ready</strong>.</p>
<h3 id="heading-visual-control">Visual control</h3>
<p>Now that our component is ready, we can see how it looks and play with it in the browser. This allows us to add the CSS and ensure we didn’t miss out on anything.</p>
<p>First, mount the component into the main <code>App.vue</code> file.</p>
<pre><code>&lt;!-- App.vue --&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">color-picker</span> <span class="hljs-attr">:swatches</span>=<span class="hljs-string">"['e3342f', '3490dc', 'f6993f', '38c172', 'fff']"</span>/&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> ColorPicker <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ColorPicker'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'app'</span>,
  <span class="hljs-attr">components</span>: {
    ColorPicker
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre><p>Then, run the app by executing the following script, and open it in your browser at <code>[http://localhost:8080/](http://localhost:8080/)</code>.</p>
<pre><code>npm run serve
</code></pre><p>You should see your color picker! It doesn’t look like much for now, but it works. Try clicking colors and change the color mode; you should see the color code change.</p>
<p>To see the component with proper styling, add the following CSS between the <code>style</code> tags:</p>
<pre><code>.color-picker {
  background-color: #fff;
  border: <span class="hljs-number">1</span>px solid #dae4e9;
  border-radius: <span class="hljs-number">0.125</span>rem;
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">2</span>px <span class="hljs-number">4</span>px <span class="hljs-number">0</span> rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  color: #<span class="hljs-number">596</span>a73;
  font-family: BlinkMacSystemFont, Helvetica Neue, sans-serif;
  padding: <span class="hljs-number">1</span>rem;
}

.swatches {
  <span class="hljs-attr">color</span>: #fff;
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: <span class="hljs-number">-0.25</span>rem <span class="hljs-number">-0.25</span>rem <span class="hljs-number">0.75</span>rem;
  padding: <span class="hljs-number">0</span>;
}

.swatch {
  border-radius: <span class="hljs-number">0.125</span>rem;
  cursor: pointer;
  height: <span class="hljs-number">2</span>rem;
  margin: <span class="hljs-number">0.25</span>rem;
  position: relative;
  width: <span class="hljs-number">2</span>rem;
}

.swatch::after {
  border-radius: <span class="hljs-number">0.125</span>rem;
  bottom: <span class="hljs-number">0</span>;
  box-shadow: inset <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span>px #dae4e9;
  content: <span class="hljs-string">''</span>;
  display: block;
  left: <span class="hljs-number">0</span>;
  mix-blend-mode: multiply;
  position: absolute;
  right: <span class="hljs-number">0</span>;
  top: <span class="hljs-number">0</span>;
}

.swatch svg {
  <span class="hljs-attr">display</span>: none;
  color: #fff;
  fill: currentColor;
  margin: <span class="hljs-number">0.5</span>rem;
}

.swatch.active svg {
  <span class="hljs-attr">display</span>: block;
}

.color-modes {
  <span class="hljs-attr">display</span>: flex;
  font-size: <span class="hljs-number">1</span>rem;
  letter-spacing: <span class="hljs-number">0.05</span>rem;
  margin: <span class="hljs-number">0</span> <span class="hljs-number">-0.25</span>rem <span class="hljs-number">0.75</span>rem;
}

.color-mode {
  <span class="hljs-attr">background</span>: none;
  border: none;
  color: #<span class="hljs-number">9</span>babb4;
  cursor: pointer;
  display: block;
  font-weight: <span class="hljs-number">700</span>;
  margin: <span class="hljs-number">0</span> <span class="hljs-number">0.25</span>rem;
  padding: <span class="hljs-number">0</span>;
  text-transform: uppercase;
}

.color-mode.active {
  <span class="hljs-attr">color</span>: #<span class="hljs-number">364349</span>;
}

.color-code {
  <span class="hljs-attr">border</span>: <span class="hljs-number">1</span>px solid #dae4e9;
  border-radius: <span class="hljs-number">0.125</span>rem;
  color: #<span class="hljs-number">364349</span>;
  text-transform: uppercase;
  padding: <span class="hljs-number">0.75</span>rem;
}
</code></pre><p>You should see something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*e2w8W0MplRF7UPdc.gif" alt="Image" width="540" height="354" loading="lazy"></p>
<p>And we’re done!</p>
<h3 id="heading-afterthoughts">Afterthoughts</h3>
<h4 id="heading-how-can-we-improve-this">How can we improve this?</h4>
<p>For now, we have a robust test suite. Even though we don’t have 100% coverage, we can feel confident with our component going out in the wild, and evolving over time. There are still a couple of things we could improve though, depending on the use case.</p>
<p>First, you may notice that when clicking the white swatch, the checkmark doesn’t show up. That’s not a bug, rather a visual issue: the checkmark is there, but we can’t see it because it’s white on white. You could add a bit of logic to fix this: when a color is lighter than a certain threshold (let’s say 90%), you could add a <code>light</code> class on the swatch. This would then let you apply some specific CSS and make the checkmark dark.</p>
<p>Fortunately, you already have all you need: the <code>color-converter</code> package can help you determine whether a color is light (with the HSL utilities), and you already have a <code>color</code> utility module to store that logic and test it in isolation. To see what the finished code could look like, check out the project’s repository on <a target="_blank" href="https://github.com/sarahdayan/colorpicker-tdd-tutorial">GitHub</a>.</p>
<p>We could also reinforce the suite by adding a few tests to make sure some expected classes are there. This doesn’t test actual logic, but would still be particularly useful if someone was relying on those class names to style the component from the outside. Again, everything depends on your use case: test what shouldn’t change without you knowing, don’t only add tests for the sake of it.</p>
<h4 id="heading-what-did-we-learn">What did we learn?</h4>
<p>There are several lessons to learn from this TDD experiment. It brings a lot to the table but also highlights a few challenges that we should be aware of.</p>
<p>First, TDD is a <strong>fantastic way to write robust tests</strong>, not too many and not too few. Have you ever finished a component, moved on to tests and thought <em>“where do I even start?”</em>? Looking at finished code and figuring out what to test is hard. It’s tempting to get it done quickly, overlook some critical parts and end up with an incomplete test suite. Or you can adopt a defensive approach and test everything, risking to focus on implementation details and writing brittle tests.</p>
<p>Adopting TDD for developing UI components helps us focus on exactly what to test by <strong>defining, before writing any line of code, if this is part of the contract or not</strong>.</p>
<p>Secondly, <strong>TDD encourages refactors, leading to better software design</strong>. When you’re writing tests after coding, you’re usually no longer in a refactoring dynamic. You can fix your code if you find issues while testing, but at this stage, you’re most likely done with the implementation. <strong>This separation between writing code and writing test is where lies the issue.</strong></p>
<p>With TDD, <strong>you’re creating a deeper connection between code and tests, with a strong focus on making the public API reliable</strong>. Implementation comes right after you’ve guaranteed the outcome. This is why the <em>green</em> step is critical: you first need your test to pass, then ensure it never breaks. Instead of implementing your way to a working solution, you’re reversing the relationship, focusing on the contract first, and allowing the implementation to remain disposable. Because refactoring comes last, and you’ve established the contract, you now have mental space to make things right, clean some code, adopt a better design, or focus on performance.</p>
<p>It’s worth noting that <strong>TDD is much easier to follow with specs</strong>. When you already have a clear overview of everything the component should do, you can translate those specifications into tests. Some teams use frameworks like <a target="_blank" href="https://en.wikipedia.org/wiki/Acceptance_test%E2%80%93driven_development">ATDD</a> (acceptance test–driven development), where the involved parties develop specifications from a business perspective. The final specs, or acceptance tests, are a perfect base to write tests following TDD.</p>
<p>On the other hand, going with TDD to test UI components can be difficult at first, and require some prior knowledge before diving into it. For starters, <strong>you need to have good knowledge of your testing libraries</strong> so that you can write reliable assertions. Look at the test we wrote with a regular expression: the syntax is not the most straightforward. If you don’t know the library well, it’s easy to write a test that fails for the wrong reasons, which would end up hindering the whole TDD process.</p>
<p>Similarly, you need to be aware of some details regarding the values you expect; otherwise, you could end up battling with your tests and doing some annoying back-and-forths. On that matter, UI components are more challenging than renderless libraries, because of the various ways the DOM specifications can be implemented.</p>
<p>Take the first test of our suite for example: we’re testing background colors. However, even though we’re passing hexadecimal colors, we’re expecting RGB return values. That’s because Jest uses <a target="_blank" href="https://github.com/jsdom/jsdom">jsdom</a>, a Node.js implementation of the DOM and HTML standards. If we were running our tests in a specific browser, we might have a different return value. This can be tricky when you’re testing different engines. You may have to seek some more advanced conversion utilities or use environment variables to handle the various implementations.</p>
<h4 id="heading-is-it-worth-it">Is it worth it?</h4>
<p>If you made it this far, you’ve probably realized that <strong>TDD demands time</strong>. This article itself is over 6,000 words! This can be a bit scary if you’re used to faster development cycles, and probably looks impossible if you’re often working under pressure. However, it’s important to bust the myth that TDD would somehow double development time for little return on investment, because this is entirely false.</p>
<p>TDD requires some practice, and you’ll get faster over time. What feels clumsy today can become a second nature tomorrow, if you do it regularly. I encourage you not to discard something because it’s new and feels awkward: give it some time to assess it fairly, then take a decision.</p>
<p>Secondly, <strong>time spent on writing test-driven code is time you won’t spend fixing bugs</strong>.</p>
<p>Fixing bugs is far more costly than preventing them. If you’ve ever had to fix critical production bugs, you know this feels close to holding an open wound on a surgical patient with one hand, while trying to operate with the other one. In the desert. At night. With a Swiss Army knife. It’s messy, stressful, suboptimal, and bears high chances of screwing up something else in the process. If you want to preserve your sanity and the trust your end users have in your software, <strong>you want to avoid those situations at all costs</strong>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*-ypCMc0eow3xfIdm.gif" alt="Image" width="640" height="360" loading="lazy"></p>
<p>Tests help you catch bugs before they make it to production, and TDD helps you write better tests. <strong>If you think you should test your software, then you should care about making these tests useful in the first place.</strong> Otherwise, the whole thing is only a waste of time.</p>
<p>As with anything, I encourage you to try TDD before discarding the idea. If you’re consistently encountering production issues, or you think you could improve your development process, then it’s worth giving it a shot. <strong>Try it for a limited amount of time, measure the impact, and compare the results.</strong> You may discover a method that helps you ship better software, and feel more confident about hitting the “Deploy” button.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An Introduction to Test-Driven Development ]]>
                </title>
                <description>
                    <![CDATA[ I’ve been programming for five years and, honestly, I have avoided test-driven development. I haven’t avoided it because I didn’t think it was important. In fact, it seemed very important–but rather b ]]>
                </description>
                <link>https://www.freecodecamp.org/news/an-introduction-to-test-driven-development-c4de6dce5c/</link>
                <guid isPermaLink="false">66d4617247a8245f78752ace</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brandon Wozniewicz ]]>
                </dc:creator>
                <pubDate>Mon, 04 Feb 2019 16:44:44 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*UILpgckM9QDwSXuy6l1WTg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I’ve been programming for five years and, honestly, I have avoided test-driven development. I haven’t avoided it because I didn’t think it was important. In fact, it seemed very important–but rather because I was too comfortable not doing it. That’s changed.</p>
<h3 id="heading-what-is-testing">What is Testing?</h3>
<p>Testing is the process of ensuring a program receives the correct input and generates the correct output and intended side-effects. We define these correct inputs, outputs, and side-effects with <em>specifications</em>. You may have seen testing files with the naming convention <code>filename.spec.js</code>. The <code>spec</code> stands for specification. It is the file where we specify or <em>assert</em> what our code should do and then test it to verify it does it.</p>
<p>You have two choices when it comes to testing: manual testing and automated testing.</p>
<h4 id="heading-manual-testing">Manual Testing</h4>
<p>Manual testing is the process of checking your application or code from the user’s perspective. Opening up the browser or program and navigating around in an attempt to test functionality and find bugs.</p>
<h4 id="heading-automated-testing">Automated Testing</h4>
<p>Automated testing, on the other hand, is writing code that checks to see if other code works. Contrary to manual testing, the specifications remain constant from test to test. The biggest advantage is being able to test <em>many</em> things much faster.</p>
<p>It’s the combination of these two testing techniques that will flush out as many bugs and unintended side-effects as possible, and ensure your program does what you say it will. The focus of this article is on automated testing, and in particular, unit testing.</p>
<blockquote>
<p>There are two main types of automated tests: Unit and End-to-End (E2E). E2E tests test an application as a whole. Unit tests test the smallest pieces of code, or units. What is a unit? Well, we define what a unit is, but in general, it’s a relatively small piece of application functionality.</p>
</blockquote>
<h4 id="heading-recap">Recap:</h4>
<ol>
<li><p>Testing is verifying our application does what it should.</p>
</li>
<li><p>There are two types of tests: manual and automated</p>
</li>
<li><p>Tests <em>assert</em> that your program will behave a certain way. Then the test itself proves or disproves that assertion.</p>
</li>
</ol>
<h3 id="heading-test-driven-development">Test-Driven Development</h3>
<p>Test-driven development is the act of first deciding what you want your program to do (the specifications), formulating a failing test, <em>then</em> writing the code to make that test pass. It is most often associated with automated testing. Although you could apply the principals to manual testing as well.</p>
<p>Let’s look at a simple example: Building a wooden table. Traditionally, we would make a table, then once the table is made, test it to make sure it does, well, what a table should do. TDD, on the other hand, would have us first define what the table should do. Then when it isn’t doing those things, add the minimum amount of “table” to make each unit work.</p>
<p>Here an example of TDD for building a wooden table:</p>
<pre><code class="language-python">I expect the table to be four feet in diameter.

The test fails because I have no table.

I cut a circular piece of wood four feet in diameter.

The test passes.

__________

I expect the table to be three feet high.

The test fails because it is sitting on the ground.

I add one leg in the middle of the table.

The test passes.

__________

I expect the table to hold a 20-pound object.

The test fails because when I place the object on the edge, it makes the table fall over since there is only one leg in the middle.

I move the one leg to the outer edge of the table and add two more legs to create a tripod structure.

The test passes.
</code></pre>
<p>This would continue on and on until the table is complete.</p>
<h4 id="heading-recap">Recap</h4>
<ol>
<li>With TDD, test logic precedes application logic.</li>
</ol>
<h3 id="heading-a-practical-example">A Practical Example</h3>
<p>Imagine we have a program that manages users and their blog posts. We need a way to keep track of the posts a user writes in our database with more precision. Right now, the user is an object with a name and email property:</p>
<pre><code class="language-js">user = { 
   name: 'John Smith', 
   email: 'js@somePretendEmail.com' 
}
</code></pre>
<p>We will track the posts a user creates in the same user object.</p>
<pre><code class="language-js">user = { 
   name: 'John Smith', 
   email: 'js@someFakeEmailServer.com'
   posts: [Array Of Posts] // &lt;-----
}
</code></pre>
<p>Each post has a title and content. Instead of storing the entire post with each user, we’d like to store something unique that could be used to reference the post. We first thought we would store the title. But, if the user ever changes the title, or if–although somewhat unlikely–two titles are exactly the same, we’d have some issues referencing that blog post. Instead, we will create a unique ID for each blog post that we will store in the <code>user</code>Object.</p>
<pre><code class="language-js">user = { 
   name: 'John Smith', 
   email: 'js@someFakeEmailServer.com'
   posts: [Array Of Post IDs]
}
</code></pre>
<h4 id="heading-set-up-our-testing-environment">Set up our testing environment</h4>
<p>For this example, we will be using Jest. Jest is a testing suite. Often, you’ll need a testing library and a separate assertion library, but Jest is an all-in-one solution.</p>
<blockquote>
<p>An assertion library allows us to make assertions about our code. So in our wooden table example, our assertion is: “I expect the table to hold a 20-pound object.” In other words, I am asserting something about what the table should do.</p>
</blockquote>
<h4 id="heading-project-setup">Project setup</h4>
<ol>
<li><p>Create an NPM project: <code>npm init</code>.</p>
</li>
<li><p>Create <code>id.js</code> and add it to the project’s root.</p>
</li>
<li><p>Install Jest: <code>npm install jest --D</code></p>
</li>
<li><p>Update the package.json <code>test</code> script</p>
</li>
</ol>
<pre><code class="language-json">// package.json

{
   ...other package.json stuff
   "scripts": {   
     "test": "jest" // this will run jest with "npm run test"
   }
}
</code></pre>
<p>That’s it for the project setup! We aren’t going to have any HTML or any styling. We are approaching this purely from a unit-testing standpoint. And, believe it or not, we have enough to run Jest right now.</p>
<p>In the command line, run our test script: <code>npm run test</code>.</p>
<p>You should have received an error:</p>
<pre><code class="language-bash">No tests found
In /****/
  3 files checked.
  testMatch: **/__tests__/**/*.js?(x),**/?(*.)+(spec|test).js?(x) - 0 matches
  testPathIgnorePatterns: /node_modules/ - 3 matches
</code></pre>
<p>Jest is looking for a file name with some specific characteristics such as a <code>.spec</code> or <code>.test</code> contained within the file name.</p>
<p>Let’s update <code>id.js</code> to be <code>id.spec.js</code>.</p>
<p>Run the test again</p>
<p>You should receive another error:</p>
<pre><code class="language-bash">FAIL  ./id.spec.js
  ● Test suite failed to run
  
Your test suite must contain at least one test.
</code></pre>
<p>A little bit better, it found the file, but not a test. That makes sense; it’s an empty file.</p>
<h4 id="heading-how-do-we-write-a-test">How Do We Write a Test?</h4>
<p>Tests are just functions that receive a couple of arguments. We can call our test with either <code>it()</code> or <code>test()</code>.</p>
<blockquote>
<p><code>it()</code>is an alias of <code>test()</code>.</p>
</blockquote>
<p>Let’s write a very basic test just to make sure Jest is working.</p>
<pre><code class="language-js">// id.spec.js

test('Jest is working', () =&gt; {
   expect(1).toBe(1);
});
</code></pre>
<p>Run the test again.</p>
<pre><code class="language-bash">PASS  ./id.spec.js
  ✓ Jest is working (3ms)
  
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.254s
Ran all test suites.
</code></pre>
<p>We passed our first test! Let’s analyze the test and results output.</p>
<p>We pass a title or description as the first argument.</p>
<p><code>test('Jest is Working')</code></p>
<p>The second argument we pass is a function where we actually assert something about our code. Although, in this case, we aren’t asserting something about our code, but rather something truthy in general that will pass, a sort of sanity check.</p>
<p><code>...() =&gt; { expect(1).toBe(1)</code> });</p>
<p>This assertion is mathematically true, so it’s a simple test to ensure we’ve wired up Jest correctly.</p>
<p>The results tell us whether the test passes or fails. It also tells us the number of tests and test suites.</p>
<h4 id="heading-a-side-note-about-organizing-our-tests">A side note about organizing our tests</h4>
<p>There is another way we could organize our code. We could wrap each test in a <code>describe</code> function.</p>
<pre><code class="language-js">describe('First group of tests', () =&gt; {
   test('Jest is working', () =&gt; {
      expect(1).toBe(1);
   });
});

describe('Another group of tests', () =&gt; {
   // ...more tests here
});
</code></pre>
<p><code>describe()</code> allows us to divide up our tests into sections:</p>
<pre><code class="language-bash">PASS  ./id.spec.js
  First group of tests
    ✓ Jest is working(4ms)
    ✓ Some other test (1ms)
  Another group of tests
    ✓ And another test
    ✓ One more test (12ms)
    ✓ And yes, one more test
</code></pre>
<p>We won’t use <code>describe</code>, but <em>it is</em> more common than not to see a <code>describe</code> function that wraps tests. Or even a couple of <code>describes</code>–maybe one for each file we are testing. For our purposes, we will just focus on <code>test</code> and keep the files fairly simple.</p>
<h4 id="heading-testing-based-on-specifications">Testing Based on Specifications</h4>
<p>As tempting as it is to just sit down and start typing application logic, a well-formulated plan will make development easier. We need to define what our program will do. We define these goals with specifications.</p>
<p>Our high-level specification for this project is to create a unique ID, although we should break that down into smaller units that we will test. For our small project we will use the following specifications:</p>
<ol>
<li><p>Create a random number</p>
</li>
<li><p>The number is an integer.</p>
</li>
<li><p>The number created is within a specified range.</p>
</li>
<li><p>The number is unique.</p>
</li>
</ol>
<h4 id="heading-recap">Recap</h4>
<ol>
<li><p>Jest is a testing suite and has a built-in assertion library.</p>
</li>
<li><p>A test is just a function whose arguments define the test.</p>
</li>
<li><p>Specifications define what our code should do and are ultimately what we test.</p>
</li>
</ol>
<h3 id="heading-specification-1-create-a-random-number">Specification 1: Create a Random Number</h3>
<p>JavaScript has a built-in function to create random numbers–<code>Math.random()</code>. Our first unit test will look to see that a random number was created and returned. What we want to do is use <code>math.random()</code> to create a number and then ensure that is the number that gets returned.</p>
<p>So you might think we would do something like the following:</p>
<p><code>expect(our-functions-output).toBe(some-expected-value)</code>. The problem with our return value being random, is we have no way to know what to expect. We need to re-assign the <code>Math.random()</code> function to some constant value. This way, when our function runs, Jest replaces <code>Math.random()</code>with something constant. This process is called <em>mocking.</em> So, what we are really testing for is that <code>Math.random()</code>gets called and returns some expected value that we can plan for.</p>
<p>Now, Jest also provides a way to prove a function is called. However, in our example, that assertion alone only assures us <code>Math.random()</code>was called somewhere in our code. It won’t tell us that the result of <code>Math.random()</code>was also the return value.</p>
<blockquote>
<p>Why would you want to mock a function? Isn’t the point to test the real code? Yes and no. Many functions contain things we cannot control, for example an HTTP request. We aren’t trying to test this code. We assume those dependencies will do what they are supposed or make pretend functions that simulate their behavior. And, in the event those are dependencies we’ve written, we will likely write separate tests for them.</p>
</blockquote>
<p>Add the following test to <code>id.spec.js</code></p>
<pre><code class="language-js">test('returns a random number', () =&gt; {
   const mockMath = Object.create(global.Math);
   mockMath.random = jest.fn(() =&gt; 0.75);
   global.Math = mockMath;
   const id = getNewId();
   expect(id).toBe(0.75);
});
</code></pre>
<h4 id="heading-breaking-the-above-test-down">Breaking the above test down</h4>
<p>First, we copy the global Math object. Then we change the <code>random</code> method to return a constant value, something we can <em>expect</em>. Finally, we replace the global <code>Math</code> object with our mocked <code>Math</code> object.</p>
<p>We should get an ID back from a function (that we haven't created yet–remember this TDD). Then, we expect that ID to equal 0.75–our mocked return value.</p>
<blockquote>
<p>Notice I’ve chosen to use a built-in method that Jest provides for mocking functions: <code>jest.fn()</code>. We could have also passed in a anonymous function instead. However, I wanted to show you this method, since there will be times that a Jest-mocked function will be required for other functionality in our tests to work .</p>
</blockquote>
<p>Run the test: <code>npm run test</code></p>
<pre><code class="language-bash">FAIL  ./id.spec.js
✕ returns a random number (4ms)
● returns a random number
   ReferenceError: getNewId is not defined
</code></pre>
<p>Notice we get a reference error just like we should. Our test can’t find our <code>getNewId()</code>.</p>
<p>Add the following code above the test.</p>
<pre><code class="language-js">function getNewId() {
   Math.random()
}
</code></pre>
<blockquote>
<p>I am keeping the code and testing in the same file for simplicity. Normally, the test would be written in a separate file, with any dependencies imported as they are needed.</p>
</blockquote>
<pre><code class="language-bash">FAIL  ./id.spec.js
   ✕ returns a random number (4ms)
   ● returns a random number
   
   expect(received).toBe(expected) // Object.is equality
   Expected: 0.75
   Received: undefined
</code></pre>
<p>We failed again with what is called an <em>assertion error</em>. Our first error was a reference error. This second error tells us it received <code>undefined</code>. But we called <code>Math.random()</code>so what happened? Remember, functions that don’t explicitly return something will implicitly return <code>undefined</code>. This error is a good hint that something wasn’t defined such as a variable, or, like in our case, our function isn’t returning anything.</p>
<p>Update the code to the following:</p>
<pre><code class="language-js">function getNewId() {
   return Math.random()
}
</code></pre>
<p>Run the test</p>
<pre><code class="language-bash">PASS  ./id.spec.js
✓ returns a random number (1ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
</code></pre>
<p>Congratulations! We passed our first test.</p>
<blockquote>
<p>Ideally, we want to get to our assertion errors as quickly as possible. Assertion errors–specifically <em>value assertion errors</em> like this one, although we will touch on <em>boolean assertions errors</em> in a bit–give us hints to what is wrong.</p>
</blockquote>
<h3 id="heading-specification-2-the-number-we-return-is-an-integer">Specification 2: The number we return is an integer.</h3>
<p><code>Math.random()</code> generates a number between 0 and 1 (not inclusive). The code we have will never generate such an integer. That’s ok though, this is TDD. We will check for an integer and then write the logic to transform our number to an integer.</p>
<p>So, how do we check if a number is an integer? We have a few options. Recall, we mocked <code>Math.random()</code> above, and we are returning a constant value. In fact, we are creating a real value as well since we are returning a number between 0 and 1 (not inclusive). If we were returning a string, for example, we couldn’t get this test to pass. Or if on the other hand, we were returning an integer for our mocked value, the test would always (falsely) pass.</p>
<p>So a key takeaway is if you going to use mocked return values, they should be realistic so our tests return meaningful information with those values.</p>
<p>Another option would be to use the <code>Number.isInteger()</code>, passing our ID as the argument and seeing if that returns true.</p>
<p>Finally, without using the mocked values, we could compare the ID we get back with its integer version.</p>
<p>Let’s look at option 2 and 3.</p>
<p><strong>Option 2: Using Number.isInteger()</strong></p>
<pre><code class="language-js">test('returns an integer', () =&gt; {
   const id = getRandomId();
   expect(Number.isInteger(id)).toBe(true);
});
</code></pre>
<p>The test fails as it should.</p>
<pre><code class="language-bash">FAIL  ./id.spec.js
✓ returns a random number (1ms)
✕ returns an integer (3ms)

● returns an integer
expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false
</code></pre>
<p>The test fails with a <em>boolean assertion error</em>. Recall, there are multiple ways a test might fail. We want them to fail with assertion errors. In other words, our assertion isn’t what we say it is. But even more so, we want our test to fail with <em>value assertion errors</em>.</p>
<p>Boolean assertion errors (true/false errors) don’t give us very much information, but a value assertion error does.</p>
<p>Let’s return to our wooden table example. Now bear with me, the following two statements might seem awkward and difficult to read, but they’re here to highlight a point:</p>
<p>First, you might assert that <strong>the table is blue [to be] true</strong>. In another assertion, you might assert <strong>the table color [to be] blue</strong>. I know, these are awkward to say and might even look like identical assertions but they're not. Take a look at this:</p>
<p><code>expect(table.isBlue).toBe(true)</code></p>
<p>vs</p>
<p><code>expect(table.color).toBe(blue)</code></p>
<p>Assuming the table isn’t blue, the first examples error will tell us it expected true but received false. You have no idea what color the table is. We very well may have forgotten to paint it altogether. The second examples error, however, might tell us it expected blue but received red. The second example is much more informative. It points to the root of the problem much quicker.</p>
<p>Let’s rewrite the test, using option 2, to receive a value assertion error instead.</p>
<pre><code class="language-js">test('returns an integer', () =&gt; {
   const id = getRandomId();
   expect(id).toBe(Math.floor(id));
});
</code></pre>
<p>We are saying we expect the ID we get from our function to be equal to the floor of that ID. In other words, if we are getting an integer back, then the floor of that integer is equal to the integer itself.</p>
<pre><code class="language-bash">FAIL  ./id.spec.js
✓ returns a random number (1ms)
✕ returns an integer (4ms)
● returns an integer
expect(received).toBe(expected) // Object.is equality

Expected: 0
Received: 0.75
</code></pre>
<p>Wow, what are the chances this function just happened to return the mocked value! Well, they are 100% actually. Even though our mocked value seems to be scoped to only the first test, we are actually reassigning the global value. So no matter how nested that re-assignment takes place, we are changing the global <code>Math</code> object.</p>
<p>If we want to change something before each test, there is a better place to put it. Jest offers us a <code>beforeEach()</code> method. We pass in a function that runs any code we want to run before each of our tests. For example:</p>
<pre><code class="language-js">beforeEach(() =&gt; {
   someVariable = someNewValue;
});

test(...)
</code></pre>
<p>For our purposes, we won’t use this. But let's change our code a bit so that we reset the global <code>Math</code> object back to the default. Go back into the first test and update the code as follows:</p>
<pre><code class="language-js">test('returns a random number', () =&gt; {
   const originalMath = Object.create(global.Math);
   const mockMath = Object.create(global.Math);
   mockMath.random = () =&gt; 0.75;
   global.Math = mockMath;
   const id = getNewId();
   expect(id).toBe(0.75);
   global.Math = originalMath;
});
</code></pre>
<p>What we do here is save the default <code>Math</code> object before we overwrite any of it, then reassign it after our test is complete.</p>
<p>Let’s run our tests again, specifically focusing back on our second test.</p>
<pre><code class="language-bash">✓ returns a random number (1ms)
✕ returns an integer (3ms)
● returns an integer
expect(received).toBe(expected) // Object.is equality

Expected: 0
Received: 0.9080890805713182
</code></pre>
<p>Since we’ve updated our first test to go back to the default <code>Math</code> object, we are truly getting a random number now. And just like the test before, we are expecting to receive an integer, or in other words, the floor of the number generated.</p>
<p>Update our application logic.</p>
<pre><code class="language-js">function getRandomId() {
   return Math.floor(Math.random()); // convert to integer
}

FAIL  ./id.spec.js
✕ returns a random number (5ms)
✓ returns an integer
● returns a random number
expect(received).toBe(expected) // Object.is equality
Expected: 0.75
Received: 0
</code></pre>
<p>Uh oh, our first test failed. So what happened?</p>
<p>Well, because we are mocking our return value. Our first test returns 0.75, no matter what. We expect, however, to get 0 (the floor of 0.75). Maybe it would be better to check if <code>Math.random()</code> gets called. Although, that is somewhat meaningless, because we could call <code>Math.random()</code>anywhere in our code, never use it, and the test still passes. Maybe, we should test whether our function returns a number. After all, our ID must be a number. Yet again, we are already testing if we are receiving an integer. And all integers are numbers; that test would be redundant. But there is one more test we could try.</p>
<p>When it is all said and done, we expect to get an integer back. We know we will use <code>Math.floor()</code> to do so. So maybe we can check if <code>Math.floor()</code> gets called with <code>Math.random()</code> as an argument.</p>
<pre><code class="language-js">test('returns a random number', () =&gt; {
   jest.spyOn(Math, 'floor'); // &lt;--------------------changed
   const mockMath = Object.create(global.Math); 
   const globalMath = Object.create(global.Math);
   mockMath.random = () =&gt; 0.75;
   global.Math = mockMath;
   const id = getNewId();
   getNewId(); //&lt;------------------------------------changed
   expect(Math.floor).toHaveBeenCalledWith(0.75); //&lt;-changed
   global.Math = globalMath;
});
</code></pre>
<p>I’ve commented the lines we changed. First, move your attention towards the end of the snippet. We are asserting that a function was called. Now, go back to the first change: <code>jest.spyOn()</code>. In order to watch if a function has been called, jest requires us to either mock that function, or spy on it. We’ve already seen how to mock a function, so here we spy on <code>Math.floor()</code>. Finally, the other change we’ve made was to simply call <code>getNewId()</code> without assigning its return value to a variable. We are not using the ID, we are simply asserting it calls some function with some argument.</p>
<p>Run our tests</p>
<pre><code class="language-bash">PASS  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
</code></pre>
<p>Congratulations on a second successful test.</p>
<h3 id="heading-specification-3-the-number-is-within-a-specified-range">Specification 3: The number is within a specified range.</h3>
<p>We know <code>Math.random()</code> returns a random number between 0 and 1 (not inclusive). If the developer wants to return a number between 3 and 10, what could she do?</p>
<p>Here is the answer:</p>
<p><code>Math.floor(Math.random() * (max — min + 1))) + min;</code></p>
<p>The above code will produce a random number in a range. Let’s look at two examples to show how it works. I’ll simulate two random numbers being created and then apply the remainder of the formula.</p>
<p><strong>Example:</strong> A number between 3 and 10. Our random numbers will be .001 and .999. I’ve chosen the extreme values as the random numbers so you could see the final result stays within the range.</p>
<p><code>0.001 * (10-3+1) + 3 = 3.008</code> the floor of that is <code>3</code></p>
<p><code>0.999 * (10-3+1) + 3 = 10.992</code> the floor of that is <code>10</code></p>
<p>Let’s write a test</p>
<pre><code class="language-js">test('generates a number within a specified range', () =&gt; {
   const id = getRandomId(10, 100);
   expect(id).toBeLessThanOrEqual(100);
   expect(id).toBeGreaterThanOrEqual(10);
});

FAIL  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer (1ms)
✕ generates a number within a specified range (19ms)

● generates a number within a specified range
expect(received).toBeGreaterThanOrEqual(expected)

Expected: 10
Received: 0
</code></pre>
<p>The floor of <code>Math.random()</code> will always be 0 until we update our code. Update the code.</p>
<pre><code class="language-js">function getRandomId(min, max) {
   return Math.floor(Math.random() * (max - min + 1) + min);
}

FAIL  ./id.spec.js
✕ returns a random number (5ms)
✓ returns an integer (1ms)
✓ generates a number within a specified range (1ms)

● returns a random number

expect(jest.fn()).toHaveBeenCalledWith(expected)

Expected mock function to have been called with:

0.75 as argument 1, but it was called with NaN.
</code></pre>
<p>Oh no, our first test failed again! What happened?</p>
<p>Simple, our test is asserting that we are calling <code>Math.floor()</code> with <code>0.75</code>. However, we actually call it with 0.75 plus and minus a max and min value that isn’t yet defined. Here we will re-write the first test to include some of our new knowledge.</p>
<pre><code class="language-js">test('returns a random number', () =&gt; {
   jest.spyOn(Math, 'floor');
   const mockMath = Object.create(global.Math);
   const originalMath = Object.create(global.Math);
   mockMath.random = () =&gt; 0.75;
   global.Math = mockMath;
   const id = getNewId(10, 100);
   expect(id).toBe(78);
   global.Math = originalMath;
});

PASS  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer
✓ generates a number within a specified range (1ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
</code></pre>
<p>We’ve made some pretty big changes. We’ve passed some sample numbers into our function (10, and 100 as minimum and maximum values), and we’ve changed our assertion once again to check for a certain return value. We can do this because we know if <code>Math.random()</code> gets called, the value is set to 0.75. And, when we apply our min and max calculations to <code>0.75</code> we will get the same number each time, which in our case is 78.</p>
<p>Now we have to start wondering if this is even a good test. We’ve had to go back in and mold our test to fit our code. That goes against the spirit of TDD a bit. TDD says to change your code to make the test pass, not to change the test to make the test pass. If you find yourself trying to fix tests so they pass, that may be a sign of a bad test. Yet, I’d like to leave the test in here, as there are a couple of good concepts. However, I urge you to consider the efficacy of a test such as this, as well as a better way to write it, or if it’s even critical to include at all.</p>
<p>Let’s return to our third test which was generating a number within a range.</p>
<p>We see it has passed, but we have a problem. Can you think of it?</p>
<p>The question I am wondering is whether we just get lucky? We only generated a single random number. What are the chances that number just happened to be in the range and pass the test?</p>
<p>Fortunately here, we can mathematically prove our code works. However, for fun (if you can call it fun), we will wrap our code in a <code>for loop</code> that runs 100 times.</p>
<pre><code class="language-js">test('generates a number within a defined range', () =&gt; {
   for (let i = 0; i &lt; 100; i ++) {
      const id = getRandomId(10, 100);    
   
      expect(id).toBeLessThanOrEqual(100);
      expect(id).toBeGreaterThanOrEqual(10);
      expect(id).not.toBeLessThan(10);
      expect(id).not.toBeGreaterThan(100);
   }
});
</code></pre>
<p>I added a few new assertions. I use the <code>.not</code> only to demonstrate other Jest API’s available.</p>
<pre><code class="language-bash">PASS  ./id.spec.js
  ✓ is working (2ms)
  ✓ Math.random() is called within the function (3ms)
  ✓ receives an integer from our function (1ms)
  ✓ generates a number within a defined range (24ms)
  
Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        1.806s
</code></pre>
<p>With 100 iterations, we can feel fairly confident our code keeps our ID within the specified range. You could also purposely try to fail the test for added confirmation. For example, you could change one of the assertions to <em>not</em> expect a value greater than 50 but still pass in 100 as the maximum argument.</p>
<h4 id="heading-is-it-ok-to-use-multiple-assertions-in-one-test">Is it ok to use multiple assertions in one test?</h4>
<p>Yes. That isn’t to say you shouldn’t attempt to reduce those multiple assertions to a single assertion that is more robust. For example, we could rewrite our test to be more robust and reduce our assertions to just one.</p>
<pre><code class="language-js">test('generates a number within a defined range', () =&gt; {
   const min = 10;
   const max = 100;
   const range = [];
   for (let i = min; i &lt; max+1; i ++) {
     range.push(i);
   }
   for (let i = 0; i &lt; 100; i ++) {
      const id = getRandomId(min, max);
      expect(range).toContain(id);
   }
});
</code></pre>
<p>Here, we created an array that contains all the numbers in our range. We then check to see if the ID is in the array.</p>
<h3 id="heading-specification-4-the-number-is-unique">Specification 4: The number is unique</h3>
<p>How can we check if a number is unique? First, we need to define what unique to us means. Most likely, somewhere in our application, we would have access to all ID’s being used already. Our test should assert that the number that is generated is not in the list of current IDs. There are a few different ways to solve this. We could use the <code>.not.toContain()</code> we saw earlier, or we could use something with <code>index</code>.</p>
<h4 id="heading-indexof"><strong>indexOf()</strong></h4>
<pre><code class="language-js">test('generates a unique number', () =&gt; {
   const id = getRandomId();
   const index = currentIds.indexOf(id);
   expect(index).toBe(-1);
});
</code></pre>
<p><code>array.indexOf()</code> returns the position in the array of the element you pass in. It returns <code>-1</code> if the array doesn’t contain the element.</p>
<pre><code class="language-bash">FAIL  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer
✓ generates a number within a defined range (25ms)
✕ generates a unique number (10ms)

● generates a unique number

ReferenceError: currentIds is not defined
</code></pre>
<p>The test fails with a reference error. <code>currentIds</code> is not defined. Let's add an array to simulate some ID’s that might already exist.</p>
<pre><code class="language-js">const currentIds = [1, 3, 2, 4];
</code></pre>
<p>Re-run the test.</p>
<pre><code class="language-bash">PASS  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer
✓ generates a number within a defined range (27ms)
✓ generates a unique number

Test Suites: 1 passed, 1 total

Tests:       4 passed, 4 total
</code></pre>
<p>While the test passes, this should once again raise a red flag. We have absolutely <em>nothing</em> that ensures the number is unique. So, what happened?</p>
<p>Again, we are getting lucky. In fact, <em>your</em> test may have failed. Although if you ran it over and over, you’d likely get a mix of both with far more passes than failures due to the size of <code>currentIds</code>.</p>
<p>One thing we could try is to wrap this in a <code>for loop</code>. A large enough <code>for loop</code> would likely cause us to fail, although it would be possible they all pass. What we could do is check to see that our <code>getNewId()</code> function could somehow be self-aware when a number is or is not unique.</p>
<p>For example. we could set <code>currentIds = [1, 2, 3, 4, 5]</code>. Then call <code>getRandomId(1, 5)</code> . Our function should realize there is no value it can generate due to the constraints and pass back some sort of error message. We could test for that error message.</p>
<pre><code class="language-js">test('generates a unique number', () =&gt; {
   mockIds = [1, 2, 3, 4, 5];
   let id = getRandomId(1, 5, mockIds);
   expect(id).toBe('failed');
    
   id = getRandomId(1, 6, mockIds);
   expect(id).toBe(6);
});
</code></pre>
<p>There are a few things to notice. There are two assertions. In the first assertion, we expect our function to fail since we constrain it in a way that it shouldn’t return any number. In the second example, we constrain it in a way where it should only be able to return <code>6</code>.</p>
<pre><code class="language-bash">FAIL  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer (1ms)
✓ generates a number within a defined range (24ms)
✕ generates a unique number (6ms)

● generates a unique number

expect(received).toBe(expected) // Object.is equality

Expected: "failed"
Received: 1
</code></pre>
<p>Our test fails. Since our code isn’t checking for anything or returning <code>failed</code>, this is expected. Although, it is possible your code received a 2 through 6.</p>
<p>How can we check if our function <em>can’t</em> find a unique number?</p>
<p>First, we need to do some sort of loop that will continue creating numbers until it finds one that’s valid. At some point though, if there are no valid numbers, we need to exit the loop so we avoid an infinite loop situation.</p>
<p>What we will do is keep track of each number we’ve created, and when we’ve created every number we can, and none of those numbers pass our unique check, we will break out of the loop and provide some feedback.</p>
<pre><code class="language-js">function getNewId(min = 0, max = 100, ids =[]) {
   let id;
   do {
      id = Math.floor(Math.random() * (max - min + 1)) + min;
   } while (ids.indexOf(id) &gt; -1);
   return id;
}
</code></pre>
<p>First, we refactored <code>getNewId()</code> to include a parameter that is a list of current ID’s. In addition, we updated our parameters to provide default values in the event they aren’t specified.</p>
<p>Second, we use a <code>do-while</code> loop since we don’t know how many times it will take to create a random number that is unique. For example, we could specify a number from 1 to 1000 with the <em>only</em> number unavailable being 7. In other words, our current ID’s only has a single 7 in it. Although our function has 999 other numbers to choose from, it could theoretically produce the number 7 over and over again. While this is very unlikely, we use a <code>do-while</code> loop since we are not sure how many times it will run.</p>
<p>Additionally, notice we break out of the loop when our ID <em>is</em> unique. We determine this with <code>indexOf()</code>.</p>
<p>We still have a problem, with the code currently how it is, if there are no numbers available, the loop will continue to run and we will be in an infinite loop. We need to keep track of all the numbers we create, so we know when we’ve run out of numbers.</p>
<pre><code class="language-js">function getRandomId(min = 0, max = 0, ids =[]) {
   let id;
   let a = [];
   do {
      id = Math.floor(Math.random() * (max - min + 1)) + min;
      if (a.indexOf(id) === -1) {
         a.push(id);
      }
      if (a.length === max - min + 1) {
         if (ids.indexOf(id) &gt; -1) {
            return 'failed';
         }
      }
   } while (ids.indexOf(id) &gt; -1);
   return id;
}
</code></pre>
<p>Here is what we did. We solve this problem by creating an array. And every time we create a number, add it to the array (unless it already in there). We know we’ve tried every number at least once when the length of that array is equal to the range we’ve chosen plus one. If we get to that point, we’ve created the last number. However, we still want to make sure the last number we created doesn’t pass the unique test. Because if it does, although we want the loop to be over, we still want to return that number. If not, we return “failed”.</p>
<pre><code class="language-bash">PASS  ./id.spec.js
✓ returns a random number (1ms)
✓ returns an integer (1ms)
✓ generates a number within a defined range (24ms)
✓ generates a unique number (1ms)

Test Suites: 1 passed, 1 total

Tests:       4 passed, 4 total
</code></pre>
<p>Congratulations, we can ship our ID generator and make our millions!</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Some of what we did was for demonstration purposes. Testing whether our number was within a specified range is fun, but that formula can be mathematically proven. So a better test might be to make sure the formula is called.</p>
<p>Also, you could get more creative with the random ID generator. For example, if it can’t find a unique number, the function could automatically increase the range by one.</p>
<p>One other thing we saw was how our tests and even specifications might crystalize a bit as we test and refactor. In other words, it would be silly to think nothing will change throughout the process.</p>
<p>Ultimately, test-driven development provides us with a framework to think about our code at a more granular level. It is up to you, the developer, to determine how granular you should define your tests and assertions. Keep in mind, the more tests you have, and the more narrowly focused your tests are, the more tightly coupled they become with your code. This might cause a reluctance to refactor because now you must also update your tests. There is certainly a balance in the number and granularity of your tests. The balance is up to you, the developer, to figure out.</p>
<p>Thanks for reading!</p>
<p>Found this helpful? I write about practical automation, productivity systems, and building smarter workflows — without the jargon. Visit me at <a href="http://brandonwoz.com">brandonwoz.com</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How and why I decided test driven development was worth my time ]]>
                </title>
                <description>
                    <![CDATA[ By Ronauli Silva I first read about test driven development (TDD) in some technical reviews blog, but I barely read it (or thought about it). Why would people write tests first when they already knew the logic? So what was this all about? Writing tes... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/test-driven-development-i-hated-it-now-i-cant-live-without-it-4a10b7ce7ed6/</link>
                <guid isPermaLink="false">66c36069c337fbd10a4b597e</guid>
                
                    <category>
                        <![CDATA[ Life lessons ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 12 May 2018 17:05:53 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*2x368zcCx_aSL57K." medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ronauli Silva</p>
<p>I first read about test driven development (TDD) in some technical reviews blog, but I <strong>barely</strong> read it (or thought about it). Why would people write tests first <strong>when they already knew the logic?</strong></p>
<p>So what was this all about? Writing tests first, incrementally building the logic, and doing it in iterations. The funny thing is, when you give two programmers five minutes to code a simple fibonacci sequence and ask one to do TDD, by the end of the 5 minutes, the programmer doing TDD may say “I have test for it!” But they won’t have finished the code. On the other hand, the other one will have finished the entire fibonacci sequence and will have optimized it.</p>
<h3 id="heading-why-use-tdd-arent-unit-tests-good-enough"><strong>Why use TDD? Aren’t unit tests good enough?</strong></h3>
<p>At the end of last year, I finally met TDD face to face. In a three-month bootcamp session, we were forced to always do things with TDD. I was already struggling enough, and so my brain always rebelled when it came time to write the tests.</p>
<p>Why should we write tests first when I can directly code the logic, my brain asked? Can’t we just write them later? After all functionality is finished?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*G2pGmoV1UXUH1izsziJDSw.png" alt="Image" width="480" height="360" loading="lazy">
<em>How it looks when our TDD mentor convince us</em></p>
<p>Let me give you a quick overview of TDD in a nutshell.</p>
<p>Let’s say I’m creating a fibonacci function. I might ask, what is the <strong>simplest</strong> assertion on a fibonacci?<br>=&gt; Returns 1 if input is 1.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*uXMbt9iEYwdXCIt7ii6Zkg.png" alt="Image" width="800" height="476" loading="lazy">
<em>Writing test first, no logic coded!</em></p>
<p>What is the <strong>simplest solution</strong> for that assertion? The <strong>simplest solution</strong>, I mean it.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*qajwrX_pTW-3LDFxY_BafQ.png" alt="Image" width="718" height="498" loading="lazy"></p>
<p>Now, next move. What is next simplest assertion for fibonacci?<br>=&gt; Returns 2 for inputs = 3</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*vKLIf8aqUSaylG2UZvP9Zg.png" alt="Image" width="778" height="476" loading="lazy"></p>
<p>Again, let’s fix this very quickly. Just return it and add some branching.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*zU1Q78Q9v3SD6LVycIrYfQ.png" alt="Image" width="782" height="666" loading="lazy"></p>
<p>Move to another expectation. Aim for a bigger number. Do it iteratively, incrementally.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*vANcpoacacpjY-HbkpEIZA.png" alt="Image" width="706" height="288" loading="lazy"></p>
<p>On and on it goes, until you get the nice solution for your fibonacci function. If you want to practice more, try adding memoization during the process (and don’t forget—with TDD).</p>
<p>Did you notice what we did there? The baby steps, your assertion, and how we define the solution? Your thought process got separated into these five critical points:</p>
<p><strong>Simple &amp; Incremental Design —</strong> You have to think about what is the simplest thing a particular function could do, and what’s coming next. The fibonacci example describes this point perfectly.</p>
<p><strong>Assertion —</strong> What is your expectation of that function? And how do you describe that expectation? Will other people understand it quickly?<br>Some test libraries provide you with a test description feature. That string is the only verbose thing that explains what your code is doing.</p>
<p>Make sure it’s a good explanation, or you’ll get a call on your holiday because your unreadable test case is failing, and no one knows why.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*B7_rBZ57kOtz92rrsWW-KA.png" alt="Image" width="800" height="287" loading="lazy">
<em>Your assertion and how you state it matters.</em></p>
<p><strong>Testable Design</strong> — How should you design it so it can be testable? Take a look at these two snippets below.</p>
<p>The first one:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*VYWzFZjaMaZj1EEBZ-TKPg.png" alt="Image" width="800" height="551" loading="lazy">
<em>Look how messy it is if your code is not testable.</em></p>
<p>By doing TDD, since you write the test first, you have to make sure that your code is <strong>testable</strong><em>.</em> You can see from the example that you don’t even test your fibonacci function. Instead, you test the <strong>side-effect</strong> of that fibonacci logic in your code, which invokes the console.log function.</p>
<p>The other thing is, you never know which one is failing, the console.log() or your fibonacci block when you refactor it. In this way, TDD leads us to increase modularity in our code.</p>
<p>Now, let’s look at second snippet.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*I2U7QrcmisWipCcYd_pcUQ.png" alt="Image" width="800" height="561" loading="lazy"></p>
<p>In the second example, we can see that we test the particular fibonacci function, not the other function that spikes on it. We are confident that the function works perfectly under the conditions that we state. We are sure that if the other function invokes our fibonacci and fails, it is not from our code.</p>
<p><strong>Negatives and Corner Cases</strong> — what do you expect when something’s not right: is it invoked with null? Does it throw an exception? How should it be handled? What could possibly happen in the code? What could be the strangest and weirdest thing that could happen in this loop? What test can catch that?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*M1cysq3GcCAVSGTSyCT1Bg.png" alt="Image" width="800" height="543" loading="lazy">
<em>How many possibilities are there?</em></p>
<p><strong>Boundaries</strong> — Should you expect that from your function? Are you sure it’s not another class’s responsibility?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*o6kKa-ib3wswzKqe.jpg" alt="Image" width="750" height="600" loading="lazy"></p>
<h3 id="heading-my-issues-with-tdd">My issues with TDD</h3>
<p>Yes, it is slow indeed. Sometimes, your time is doubled since you’re writing both tests and logic at the same time. This makes how you use your keyboard important (typing speed, better shortcut usage, and so on).</p>
<p>And even worse —when the requirements change—you have to refactor or delete and rewrite test code you worked hard on. Which means that tests code is code you write that is more likely to be deleted in the future. And you are doing it, iteratively. DELETES. CODES. REWRITES. AGAIN. IN A LOOP!</p>
<p><strong>Think about it. Why would you write code that is more likely to be deleted?</strong></p>
<p>“Nope, that’s enough of this TDD thing. I’ll do it when I find a strong reason why I should spend time writing code I’m likely to delete”, I said to myself.</p>
<p><strong>And that was right before I unconsciously started digging my own grave.</strong></p>
<h3 id="heading-why-i-changed-my-mind">Why I changed my mind</h3>
<p>The enlightenment came about two months later, when I was assigned to a group that did not implement TDD well at all.</p>
<p>I mean, they implemented TDD, <strong>but</strong> they left the tests broken. They didn’t bother to fix those failing test cases (which often broke because the requirements had changed). And this happened because of the most cliche reason in the world: they didn’t have time. They had to make deadlines.</p>
<p>After looking at the situation, I mumbled “Look, see! This TDD doesn’t work in the production world!” It made me question many things: is this TDD worth fighting for? Is TDD worth the time? Does it even deliver any business value?</p>
<p>After a while, I realized that the problems were growing exponentially, tasks were getting delayed, chaos was reigning, and the developer experience was getting really bad — all because they implemented TDD poorly and halfheartedly. It was <strong>even worse than not writing tests at all.</strong></p>
<p>Here are some of the issues it caused:</p>
<ul>
<li>When I added a new feature or refactored things, I didn’t know whether that code was failing or not because the test was already failing.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*qL_hflKv-kH7IOjxfnqQqg.png" alt="Image" width="800" height="296" loading="lazy">
<em>We do not know which tests do I fails on, because almost all of it already failing before! -</em>-_</p>
<ul>
<li>We were forced to have high threshold on code coverage. And make no mistake, programmers are smart and <strong>sneaky</strong>. They write tests with no expectations, like smoke tests. And that was the <strong>only</strong> test they had on that particular logic. It was like, we only knew it was failing after everything was on fire. How dangerous.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*Gq_uwGye0DYRcXA822w1fA.png" alt="Image" width="800" height="345" loading="lazy">
<em>Always passing, anyway! All hail code coverage!</em></p>
<ul>
<li>We used CI/CD for deployment. And we always deployed even though it was failing, which was scary: You never knew whether your production itself was failing, or if it was because you didn’t fix the tests.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*g_0sJ3rQKpauqi3wuLzD0g.png" alt="Image" width="800" height="414" loading="lazy">
<em>Test is failing, deploy anyway!</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*8R6C2z00Z6f7F7fC.jpg" alt="Image" width="640" height="480" loading="lazy"></p>
<ul>
<li>After production, we ended up fixing strange and completely out-of-mind bugs. We had never even thought of those strange conditions before. (Ever find a situation when something in a try-catch block is failing but not throwing an exception?)</li>
</ul>
<p>Oh, the horror!</p>
<p>After analyzing the situation, doing it in iterations, and reflecting on it, I realized that TDD is actually a golden nugget. If done right, it can make us better developers.</p>
<h3 id="heading-why-i-now-love-tdd">Why I now love TDD</h3>
<h4 id="heading-with-tdd-you-have-fewer-bugs"><strong>With TDD, you have fewer bugs</strong></h4>
<p><strong>You’ll hardly miss things that you can catch with your tests</strong>.</p>
<p>When you get a requirement, you write a test for it first. Then you run the test, and see if it fails first. When you add the logic, you see if it passes.</p>
<p><strong>Seeing it fail is important, because you know what broke your code</strong>. In the long run, this practice ensures that all lines in your code are well-tested.</p>
<h4 id="heading-tdd-saves-you-lot-of-time-in-the-future"><strong>TDD saves you lot of time <em>(in the future)</em></strong></h4>
<p>CI/CD relies heavily on tests. If you write the wrong tests (or too few tests) you already wasted five hours to find what errors it couldn’t catch. If you write good tests, and spend just five more minutes writing deeper and more complete conditions of your code, you’ll save time debugging it in the future.</p>
<h4 id="heading-tdd-deals-with-the-human-aspects-of-coding"><strong>TDD deals with the human aspects of coding</strong></h4>
<p>The main ones being negligence and forgetfulness. If you write all the logic directly, by the end of, say, line 190, you may forget why you multiplied a variable by 100 at line 19.</p>
<p>But, by doing it incrementally and stating the assertion of our code, we gradually build our understanding. This makes us understand the code and its behaviors better.</p>
<p>As a bonus, we have sort of living and functional documentation of our code. You can see which test is failing if you delete the previous line, and you instantly know why.</p>
<h4 id="heading-tdd-helps-you-focus"><strong>TDD helps you focus</strong></h4>
<p>Programmers tend to write too much code, or write code that does too much. Or they try to plan for conditions that never exist. Often, when my team practiced pair pairing, I discovered that TDD allowed us to write less code compared to other teams that didn’t do TDD. While coding, we were focused on getting the test case passed — nothing less, nothing more.</p>
<h4 id="heading-tdd-also-benefits-your-brain"><strong>TDD also benefits your brain</strong></h4>
<p>You have proof of your code’s readiness for production, even before deploying it. You don’t have to worry about things you already tested for before. You don’t have to brag to your project manager about how project is going, because you can show them that the tests are passing!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*m9IeLR30F2AAtlwu.jpg" alt="Image" width="800" height="683" loading="lazy"></p>
<p>However, TDD is not <strong>always</strong> your silver bullet. It takes time. You have to set up the project — such as the environment, mocks, and stubs — even before you start doing anything.</p>
<p>But remember, time spent on writing tests is not wasted time. It’s the time you invest now to save your time later. It’s the investment you make on the system you build, as you build code on top of more code. And you want to make its foundation as solid as possible. TDD gives you that.</p>
<p>In the end, it could cost you a fortune if you <strong>don’t</strong> do TDD. <strong>It may take time, but it is good for you and your team in the long run.</strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Observations on the testing culture of Test Driven Development ]]>
                </title>
                <description>
                    <![CDATA[ By Doug Arcuri This is not a primer on Test Driven Development. It contains my personal observations of re-starting the discipline and the problem of unit testing craft. Kent Beck, a software engineering leader, is also the modern day re-inventor of ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/8-observations-on-test-driven-development-a9b5144f868/</link>
                <guid isPermaLink="false">66c341a81730faaceeb438d0</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 02 Mar 2018 17:42:42 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*s1wnrbNeea89uz6GsPe6jw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Doug Arcuri</p>
<p><em>This is not a primer on Test Driven Development. It contains my personal observations of re-starting the discipline and the problem of unit testing craft.</em></p>
<p>Kent Beck, a software engineering leader, is also the modern day re-inventor of test driven development (TDD). Kent also cowrote JUnit, a widely used testing framework, with Erich Gamma.</p>
<p>In his book, <a target="_blank" href="https://www.pearson.com/us/higher-education/program/Beck-Extreme-Programming-Explained-Embrace-Change-2nd-Edition/PGM155384.html">XP Explained</a> (second edition), Kent describes that at the intersection of <strong>values</strong> and <strong>practices</strong> form <strong>principles</strong>. When we iterate from the concept and plug in what we believe as a formula, we achieve a transformation.</p>
<pre><code>[KISS, Quality, YAGNI, ...] + [Testing, Specs, ...] == [TDD, ...]
</code></pre><p>I have a profound respect for Kent’s life work not only because of his brilliant software creations but also his continued exploration of <strong>trust</strong><em>,</em> <strong>courage</strong><em>,</em> <strong>feedback</strong><em>,</em> <strong>simplicity</strong> and <strong>vulnerability</strong><em>.</em> All attributes are paramount to the invention of Extreme Programming (XP).</p>
<p>TDD is a principle and a <strong>discipline</strong> that is followed by the XP community. The discipline has been present for nineteen years.</p>
<p>In this post, I will describe my opinion of where TDD stands in its adoption. Following this, we will explore intriguing personal observations as we perform TDD. Finally, we will conclude by postulating why TDD hasn’t taken off as it should. Let’s begin.</p>
<h3 id="heading-tdd-studies-and-professionalism">TDD, Studies, And Professionalism</h3>
<p>Nineteen years in, TDD is still debated as a discipline in the development community.</p>
<p>The first question an analytical person would ask, is “How many or what percentage of software professionals use TDD today?” If you asked a friend of Robert Martin (Uncle Bob), a friend of Kent Beck, the answer would be one hundred percent. This is because Uncle Bob believes that it is infeasible to consider being a professional if test driven development is not practiced. [1]</p>
<p>Uncle Bob has been the focus of the discipline for some years now and it is natural to discuss him as a part of this write up. Uncle Bob has defended TDD and has pushed the discipline’s boundaries significantly. It should go without question that I too respect Uncle Bob and his pragmatic dogmatism.</p>
<p>However, no one asks the follow up question “the definition of <strong>practice</strong> is the deliberate use of — but it does not specify amount or percentage of, right?” My subjective estimation is that a majority have not practiced TDD even in some small timeframe.</p>
<p>The reality of the situation is that we actually <strong>do not know,</strong> since the practice percentage has not been studied widely. The only concrete measurement we have is a small collection of companies being gathered at <a target="_blank" href="http://www.wedotdd.com/">WeDoTDD</a>. Here, there is tracking of such companies. Interviews are conducted with those who practice 100% of the time, but that list is small. It is also incomplete since simple searching reveals other larger shops practicing — but perhaps not at full capacity.</p>
<p>If we don’t know how many are practicing, the next question is “how effective is TDD based on measured benefits?”</p>
<p>You would be pleased to know that there have been studies conducted over the years that have proven TDD’s effectiveness. This includes the well recognized reports from <a target="_blank" href="https://collaboration.csc.ncsu.edu/laurie/Papers/Unit_testing_cameraReady.pdf">Microsoft</a>, <a target="_blank" href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.567.3740&amp;rep=rep1&amp;type=pdf">IBM</a>, North Carolina University, and the <a target="_blank" href="http://www.sserg.org/publications/uploads/04b700e040d0cac8681ba3d039be87a56020dd41.pdf">University of Helsinki</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/SxfOzMZHoqcB8MJ51eU97aeXKATgYWYxG7Ms" alt="Image" width="800" height="344" loading="lazy">
<em>An impactful visual taken from the Helsinki report.</em></p>
<p>These reports prove to a degree that defect density is reduced by 40% to 60% in exchange for increased effort and execution time by 15% to 35%. These numbers have also begun to echo through books and new industry processes such as the DevOps community.</p>
<p>With these questions half answered, the final question is “what should I expect as I start to perform TDD?” You are in luck, because I have formulated my own observations of TDD. Let’s review them next.</p>
<h3 id="heading-1-tdd-commands-verbalizing-an-approach">1. TDD Commands Verbalizing An Approach</h3>
<p>As we practice TDD, we begin to experience a phenomena of “calling the shot”. In simple terms, the short acts of creating failing and passing tests will intellectually challenge the developer. They will say aloud “I think this will pass” and “I do not think this will pass” or “I’m not sure, let me think after I try this approach.”</p>
<p>The developer’s IDE has become a rubber duck begging for an intense conversation. At a minimum, TDD shops should be humming with this type of conversion.</p>
<blockquote>
<p><em>Think, then speak up about your immediate next move(s).</em></p>
</blockquote>
<p>This type of reinforcement is key to communication, not only to predict your next action, but also to reinforce the concepts of writing the <strong>simplest</strong> code to make a unit test pass. Of course, if the developer becomes silent, they are almost certainly wandering off the loop and must come back on the path.</p>
<h3 id="heading-2-tdd-commands-muscle-memory">2. TDD Commands Muscle Memory</h3>
<p>As a developer moves forward with the first cycles of TDD, they will experience heavy fatigue by battling through high friction and awkward flow. This is true for any initiated but unlearned human activity. The developer will attempt to find shortcuts to improve the cycle, because the goal is to reduce that awkwardness and to improve muscle memory.</p>
<p>Muscle memory is a key to feeling the good vibes and becoming fluid. TDD demands it because of execution repetition.</p>
<blockquote>
<p><em>Print out a shortcut cheat sheet. Learn only as many shortcuts in your IDE as you need to make your cycles efficient. Then, keep searching for more.</em></p>
</blockquote>
<p>The developer will become an expert of select shortcuts only in a matter of a few sittings, including building and running the test rig. With more practice, creating new artifacts, highlighting text, and navigating the IDE will become natural. Finally we graduate to unlock all of the refactor shortcuts such as extraction, renaming, generation, pulling up, reformatting, and pushing down code.</p>
<h3 id="heading-3-tdd-commands-thinking-at-least-slightly-forward">3. TDD Commands Thinking At Least Slightly Forward</h3>
<p>Each time a developer sits to start TDD, they must have a concrete short mental map on what is to be solved. In a traditional coding approach, this is not always true, as the mental map of the solve could be macro and exploratory. The developer does not know how to solve the problem, but may know of a fuzzy goal. To get to that goal, unit tests are neglected in the process.</p>
<p>The start and end of the sitting should also be ritualized. First, think and list. Play with it. List more. Then start, do, and then think. Check off. Repeat some times. Finally think and stop.</p>
<blockquote>
<p><em>Maintain your test list like a hawk. Check off items as you go. Never drive without one. Think!</em></p>
</blockquote>
<p>The list may take some time to formulate and is not a part of the cycle. However it should be prepared right before the cycles start. If you don’t have one, you may not know where you are going. Always have a map.</p>
<pre><code><span class="hljs-comment">// A Test List// "" -&gt; does not validate// "a" -&gt; does not validate// "aa" -&gt; validates// "racecar" -&gt; validates// "Racecar" -&gt; validates// print the validation// have a blueberry ale</span>
</code></pre><p>The developer must command a <strong>test list</strong>, as described by Kent Beck. The test list allows direction of solving in the next immediate cycles. That test list should always be labored upon and updated moments before the cycles begin. Once the test list is solved minus the last step, the cycle stops on red with a failing test.</p>
<h3 id="heading-4-tdd-demands-communication-with-others">4. TDD Demands Communication With Others</h3>
<p>As the above test list is filled out, certain steps may become blocked because the commitment of work was not clear. The developer cannot figure out the test list. Or the reverse. Generating a presumptive test list that has too many guesses about the missing requirement(s). The suggestion is to stop right there.</p>
<p>Driving without TDD will cause implementations of unneeded complexity to occur. Driving with TDD in listless mindlessness is just as dangerous.</p>
<blockquote>
<p><em>Speak up loudly if the test list has gaps.</em></p>
</blockquote>
<p>In TDD, the developer must understand what to build based on the owner’s picture of the requirement(s) and no more. If the requirement is unclear in context, the test list will start to break down. That break down will require a conversation. Candid conversions can quickly turn into trust and respect. The short feedback loops are now established.</p>
<h3 id="heading-5-tdd-demands-iterative-architecture">5. TDD Demands Iterative Architecture</h3>
<p>Initially proposed in the first edition of the XP book, Kent proposed that tests should drive architecture. However, over the course of a few years there have been stories about how sprint teams crash into walls about a few sprints in.</p>
<p>Of course, having tests drive all of the architecture is unwise. Uncle Bob had agreed with other experts that architecture driven by tests is “horse sh*t.” [1] Some larger map is required, but not too far above the distributed test lists that are being worked on in the field.</p>
<p>Kent also called this out many years ago in the <a target="_blank" href="https://www.safaribooksonline.com/library/view/test-driven-development/0321146530/">TDD By Example</a> book. <strong>Concurrency</strong> and <strong>security</strong> are the two major areas where TDD cannot drive and the developer must be concerned separately. Loosely translated, concurrency via system design is on a different level and must be labored over iteratively and in concert with TDD. This is very true today, as some architectures are driving toward reactive and reactive extensions, the zenith of concurrency construction.</p>
<blockquote>
<p><em>Create a larger map of organization. A vision that goes just a little bit ahead. Make sure you are steering with the team in the same way.</em></p>
</blockquote>
<p>However, the most important idea is the <strong>organization</strong> of the system which TDD cannot effectively handle alone. This is because unit tests test at a lower level. Iterative architecture and TDD orchestration is hard in practice and demands trust among all team members, pair programming, and solid code review. There is no clear way to do this, but it will become apparent that short iterative design sessions are needed in unison with the test lists in the field.</p>
<h3 id="heading-6-tdd-reveals-unit-test-frailty-and-degenerative-implementation">6: TDD Reveals Unit Test Frailty And Degenerative Implementation</h3>
<p>Unit tests have a funny property about them and TDD exposes that property. They cannot prove correctness. E.W. Dijkstra had labored over this and discussed the possibility of mathematical proofs in our profession to resolve the gap.</p>
<p>For example, the below solves all tests around a hypothetical imperfect palindrome that business required. It was developed with TDD.</p>
<pre><code><span class="hljs-comment">// Not an imperfect palindrome.</span>
</code></pre><pre><code>@Testfun <span class="hljs-string">`Given "", then it does not validate`</span>() {    <span class="hljs-string">""</span>.validate().shouldBeFalse()}@Testfun <span class="hljs-string">`Given "a", then it does not validate`</span>() {    <span class="hljs-string">"a"</span>.validate().shouldBeFalse()}@Testfun <span class="hljs-string">`Given "aa", then it validates`</span>() {    <span class="hljs-string">"aa"</span>.validate().shouldBeTrue()}@Testfun <span class="hljs-string">`Given "abba", then it validates`</span>() {    <span class="hljs-string">"abba"</span>.validate().shouldBeTrue()}@Testfun <span class="hljs-string">`Given "racecar", then it validates`</span>() {    <span class="hljs-string">"racecar"</span>.validate().shouldBeTrue()}@Testfun <span class="hljs-string">`Given "Racecar", then it validates`</span>() {    <span class="hljs-string">"Racecar"</span>.validate().shouldBeTrue()}
</code></pre><p>Indeed, these tests have holes. Unit tests are frail even for the most trivial asks. We can never prove correctness because if we had to, it would require an extreme mental labor and the required inputs would be unimaginable.</p>
<pre><code><span class="hljs-comment">// Too generic of a solve based on tests provided</span>
</code></pre><pre><code>fun <span class="hljs-built_in">String</span>.validate() = <span class="hljs-keyword">if</span> (isEmpty() || length == <span class="hljs-number">1</span>) <span class="hljs-literal">false</span> <span class="hljs-keyword">else</span> toLowerCase() == toLowerCase().reversed()
</code></pre><pre><code><span class="hljs-comment">// Is the best implementation and solves all tests</span>
</code></pre><pre><code>fun <span class="hljs-built_in">String</span>.validate() = length &gt; <span class="hljs-number">1</span>
</code></pre><p><code>length &gt;</code>; 1 could be call<strong>ed degenerative implementat</strong>ion. It is just enough implementation to solve the problem at hand, but on its own tells us nothing about the problem we are trying to solve.</p>
<p>The question is, when does an developer stop writing the tests? The answer seems to be simple. When the <strong>business is satisfied</strong>, not when the code author is. This may hurt our <strong>construction passion</strong> and we are <strong>embarrassed by the simplicity</strong><em>.</em> These feelings are balanced by the good feelings of clean code and the ability to refactor with confidence later. Things simply feel tidy and clean.</p>
<blockquote>
<p><em>Be aware that the unit tests are fallible but are necessary. Understand their strength and weakness. <a target="_blank" href="http://pitest.org/">Mutation testing</a> may help tie up this gap.</em></p>
</blockquote>
<p>TDD has gains, but it can take away building the sand castles we do not need. It is <strong>constraint</strong> but it allows us to go faster, further and with safety. Perhaps this is what Uncle Bob really meant about being a <strong>professional</strong>.</p>
<p>But! No matter how frail unit tests may seem, they are a core necessity. They are required to allow <strong>fear</strong> to turn into <strong>courage</strong>. Tests allow those to mercifully refactor the code and even better, it is a guide, a <strong>documentation</strong>, for any other developer to immediately jump in and being to add value to a project that is well supported by unit testing.</p>
<h3 id="heading-7-tdd-reveals-assertion-completion-feedback-loop">7: TDD Reveals Assertion Completion Feedback Loop</h3>
<p>Take a step back further. For the next two phenomena, we will visit strange re-occurrences. For the first occurrence, let’s take a quick look at FizzBuzz. Here is our test list.</p>
<pre><code><span class="hljs-comment">// Print numbers 9 to 15. [OK]// For numbers divisible by 3, print Fizz instead of the number.// ...</span>
</code></pre><p>We are a few steps in. We now have a failing test.</p>
<pre><code>@Testfun <span class="hljs-string">`Given numbers, replace those divisible by 3 with "Fizz"`</span>() {    val machine = FizzBuzz()    assertEquals(machine.print(), <span class="hljs-string">"?"</span>)}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FizzBuzz</span> </span>{    fun print(): <span class="hljs-built_in">String</span> {        <span class="hljs-keyword">var</span> output = <span class="hljs-string">""</span>        <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> <span class="hljs-number">9.</span><span class="hljs-number">.15</span>) {            output += <span class="hljs-keyword">if</span> (i % <span class="hljs-number">3</span> == <span class="hljs-number">0</span>) {                <span class="hljs-string">"Fizz "</span>            } <span class="hljs-keyword">else</span> <span class="hljs-string">"${i} "</span>        }        <span class="hljs-keyword">return</span> output.trim()    }}
</code></pre><pre><code>Expected &lt;Fizz <span class="hljs-number">10</span> <span class="hljs-number">11</span> Fizz <span class="hljs-number">13</span> <span class="hljs-number">14</span> Fizz&gt;, actual &lt;?&gt;.
</code></pre><p>Naturally, if we duplicate the expected assertion data to <code>assertEquals</code>, it achieves the result and the test passes.</p>
<blockquote>
<p><em>As we keep querying the test rig during implementation steps, failing unit tests set around data may correctly answer their own assertions. Perhaps we can call this voodoo testing.</em></p>
</blockquote>
<p>Sometimes failing tests will scream a correct result that is required to make the test pass. I do not know what to call these events… perhaps <strong>voodoo testing</strong><em>.</em> Your milage may vary based on your laziness and test etiquette, but I have seen this happen numerous times when working to have implementation achieve canned and expected <strong>data sets</strong><em>.</em></p>
<h3 id="heading-8-tdd-reveals-the-transformation-priority-premise">8: TDD Reveals The Transformation Priority Premise</h3>
<p>In TDD, one can become trapped. There are situations where the developer can be entangled by the transformations they apply to achieve implementation. At some point, the testing code becomes a bottle neck to move forward. An <strong>impasse</strong> forms. The developer has to back out, and disarm by removing a portion of tests to get out of the hole. The developer becomes exposed.</p>
<p>Uncle Bob likely has experienced these impasses in his career, and then he probably realized that the act of making a test pass must require a preferred order so that the risk of a impasse is reduced. At the same time, he also would’ve realized a premise. <strong>As the tests get more specific, the code gets more generic.</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ABgDg1ObAdd7zqhYFkN0shypQX89fqaAC9AP" alt="Image" width="732" height="266" loading="lazy">
<em>The order of the transformations. One should always prefer the simplest (top of the list).</em></p>
<p>This is called the <a target="_blank" href="https://8thlight.com/blog/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html">Transformation Priority Premise</a>. There seems to be an order of refactor risk one can chose to achieve by passing a test. The top transformation chosen (the simplest) is usually the best option and will incur the least risk to create a situation of an impasse.</p>
<p><a target="_blank" href="http://blog.cleancoder.com/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html">TPP</a> or perhaps <strong>Uncle Bob’s Test Calculus</strong> is one of the most intriguing, technical, and exciting observations to date. Use it as a guide to keep the code as simple as possible.</p>
<blockquote>
<p><em>Print out the TPP list and place it at your desk. Refer to it as you drive to avoid impasses. Embrace an order of simplicity.</em></p>
</blockquote>
<p>This completes all initial observations. But before we conclude, I’d like to get back to my original unanswered question “How many or what percentage of software professionals use TDD today?” My answer stands at “I think the group is small”. I’d like to explore this guess below with reasons why.</p>
<h3 id="heading-has-tdd-taken-off">Has TDD Taken Off?</h3>
<p>Unfortunately it hasn’t. The percentage is subjectively low and the search for data continues. Taking from my experiencing in hiring, leading teams, and being an empathic developer myself, let me rely my observations.</p>
<h4 id="heading-reason-1-no-exposure-to-real-testing-culture">Reason 1: No Exposure To Real Testing Culture</h4>
<p>My educated guess is that a majority of software developers have not had the experience of learning and working through a <strong>testing culture</strong>.</p>
<p>The definition of a testing culture is a place where developers are deliberately practicing and improving by testing. They are continuously mentoring those who are not skilled in the area. Each pairing and in every pull request is a feedback loop on building individuals to become great at testing. There is also major support and backing all the way up the engineering chain. All managers understand and believe in testing. When deadlines and times get tough, the test discipline is not dropped — it is maintained.</p>
<p>Those that have gone through a testing culture, like myself, are lucky to have those observations. We can apply the experience to future projects.</p>
<h4 id="heading-reason-2-unclear-educational-resources">Reason 2: Unclear Educational Resources</h4>
<p>Some have attempted to write books on the subject such as <a target="_blank" href="http://xunitpatterns.com/">xUnit Patterns</a> and <a target="_blank" href="https://www.manning.com/books/effective-unit-testing">Effective Unit Testing</a>. However, there seems to be no place that clearly defines what and why to test. Most resources out there do not clearly describe the craft of assertion and verification.</p>
<p>Open source projects are also hit or miss with good unit tests. In these unfamiliar projects, the very first thing I do is look for tests. My disappointment is almost certain. I can also remember the very few instances of excitement when tests are present but also… readable.</p>
<h4 id="heading-reason-3-no-focus-in-universities">Reason 3: No Focus In Universities</h4>
<p>My observation of candidates over the years fresh out of university reveals a well-known assumption: little to no discipline in testing rigor. Every developer I know has learned testing afterward, some on their own but most going through a previous testing culture experience.</p>
<h4 id="heading-reason-4-a-career-of-high-test-passion-required">Reason 4: A Career Of High Test Passion Required</h4>
<p>It also takes passion to be interested in testing and to understand the details and benefits over a large time period. You have to be hungry and obsess on clean code and doing the craft better.</p>
<p>Most just want to get things working, achieving only half of what Kent Beck said “First make it work, then make it right.” I empathize that to get things working is a tough battle in itself.</p>
<p>Testing is just as hard to do well, so let’s conclude on that thought.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Kent’s proposal in XP included a simple formulation of <strong>instinct</strong>, <strong>thought</strong>, and <strong>experience</strong>. These three levels are stepping stones to execution quality measured by a <strong>threshold</strong>. This is a great model to explain a problem with TDD.</p>
<p>The threshold for clean test execution is high, in that it eclipses a generous baseline of experience. The majority will never become above water and those that do are lucky — have experience from the elusive testing culture.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/I3qtB4KmCS9URHBFHSyqTTyilaoBmrf6-3Lk" alt="Image" width="800" height="328" loading="lazy">
<em>From XP Explained. Originally about design quality, imagine a higher threshold line.</em></p>
<p>Software is tough enough to build and organize, but testing takes it to a whole new level of enlightenment.</p>
<p>Early on, I had an <strong>instinct</strong> that testing is important, but my test culture <strong>experience</strong> came later. It took years of <strong>thought</strong> in my career, but without that experience of test culture, I would have not emerged above that threshold.</p>
<p>I believe that many developers also have this thought but cannot see the true benefit of test culture due to lack of specific <strong>experience</strong>.</p>
<blockquote>
<p><em>TDD discipline has struggled to take off due in part to high learning curve of testing. Even armed with veteran testing knowledge and experience, TDD requires a headspace that is unique and challenging. However, all should try it.</em></p>
</blockquote>
<p>Amplify this. TDD demands all that <strong>thought</strong> and <strong>experience</strong> and more<em>.</em> It is not easy and is a skill. I think it is because it commands the developers throughput to the maximum, continuously and relentlessly. We are all <strong>vulnerable</strong> in the process, and few developers like being in this position.</p>
<pre><code>@Testfun <span class="hljs-string">`Given software, when we build, then we expect tests`</span>() {    build(software) shoudHave tests}
</code></pre><p>However, TDD is an intriguing discipline and <strong>is a tool to lean on</strong>. Its <strong>phenomena</strong> should be studied in detail. If anything else, the discipline makes for better developers as the practice contains benefits which can strengthen the individual and collective group.</p>
<p><em>Inspiration for this post was due in part by <a target="_blank" href="https://www.freecodecamp.org/news/8-observations-on-test-driven-development-a9b5144f868/undefined">Danny Preussler</a>. As I re-explore the discipline, he has started running comprehensive Android TDD workshops. <a target="_blank" href="https://speakerdeck.com/dpreussler/tdd-on-android-mobos-2018">Check out his recent deck here</a>.</em></p>
<p>[1] <a target="_blank" href="https://www.youtube.com/watch?v=KtHQGs3zFAM">Jim Coplien and Bob Martin Debate TDD</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to DRY out your RSpec Tests using Shared Examples ]]>
                </title>
                <description>
                    <![CDATA[ By Parth Modi “Give me six hours to chop down a tree and I will spend the first four sharpening the axe.” — Abraham Lincoln When I refactored a project a few weeks ago, I spent most of my time writing specs. After writing several similar test cases... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-dry-out-your-rspec-tests-using-shared-examples-d5cc5d33fd76/</link>
                <guid isPermaLink="false">66c351cb765a634c3485fe0c</guid>
                
                    <category>
                        <![CDATA[ #rspec ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ruby ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ruby on Rails ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 04 Feb 2017 00:00:00 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*5Cb4TjFan4h4eM3JsCqrbA.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Parth Modi</p>
<blockquote>
<p>“<em>Give me six hours to chop down a tree and I will spend the first four sharpening the axe.” — Abraham Lincoln</em></p>
</blockquote>
<p>When I refactored a project a few weeks ago, I spent most of my time writing specs. After writing several similar test cases for some APIs, I started to wonder whether I might be able to get rid of a lot of this duplication.</p>
<p>So I threw myself into reading up on the best practices for DRYing up tests (Don’t Repeat Yourself). And that’s how I came to know of <code>shared examples</code> and <code>shared contexts</code>.</p>
<p>In my case, I ended up using shared examples. And here’s what I’ve learned so far from applying these.</p>
<p>When you have multiple specs that describe similar behavior, it might be better to extract redundant examples into <code>shared examples</code> and use them in multiple specs.</p>
<p>Suppose you have two models <em>User</em> and <em>Post</em>, and a user can have many posts. Users should be able to view list of users and posts. Creating an index action in the users and posts controllers will serve this purpose.</p>
<p>First, write specs for your index action for the users controller. It will have the responsibility of fetching users and rendering them with proper layout. Then write enough code to make tests pass.</p>
<pre><code># users_controller_spec.rbdescribe <span class="hljs-string">"GET #index"</span> <span class="hljs-keyword">do</span>  before <span class="hljs-keyword">do</span>     <span class="hljs-number">5.</span>times <span class="hljs-keyword">do</span>      FactoryGirl.create(:user)     end    get :index  end  it {  expect(subject).to respond_with(:ok) }  it {  expect(subject).to render_template(:index) }  it {  expect(assigns(:users)).to match(User.all) }end
</code></pre><pre><code># users_controller.rbclass UsersController &lt; ApplicationController  ....  def index    @users = User.all  end  ....end
</code></pre><p>Typically, the index action of any controller fetches and aggregates data from few resources as required. It also adds pagination, searching, sorting, filtering and scoping.</p>
<p>Finally, all these data are presented to views via HTML, JSON, or XML using APIs. To simplify my example, the index actions of controllers will just fetch data, then show them via views.</p>
<p>The same goes for the index action in the posts controller:</p>
<pre><code>describe <span class="hljs-string">"GET #index"</span> <span class="hljs-keyword">do</span>   before <span class="hljs-keyword">do</span>     <span class="hljs-number">5.</span>times <span class="hljs-keyword">do</span>      FactoryGirl.create(:post)    end    get :index  end  it {  expect(subject).to respond_with(:ok) }  it {  expect(subject).to render_template(:index) }  it {  expect(assigns(:posts)).to match(Post.all) }end
</code></pre><pre><code># posts_controller.rbclass PostsController &lt; ApplicationController  ....  def index    @posts = Post.all  end  ....end
</code></pre><p>RSpec tests written for both users and posts controller are very similar. In both controllers we have:</p>
<ul>
<li>The response code — should be ‘OK’</li>
<li>Both index action should render proper partial or view — in our case <code>index</code></li>
<li>The data we want to render, such as posts or users</li>
</ul>
<p>Let’s DRY the specs for our index action by using <code>shared examples</code>.</p>
<h3 id="heading-where-to-put-your-shared-examples">Where to put your shared examples</h3>
<p>I like to place shared examples inside the _specs/support/shared<em>examples</em> directory so that all <code>shared example</code>-related files are loaded automatically.</p>
<p>You can read about other commonly used conventions for locating your <code>shared examples</code> here: <a target="_blank" href="https://www.relishapp.com/rspec/rspec-core/docs/example-groups/shared-examples">shared examples documentation</a></p>
<h3 id="heading-how-to-define-a-shared-example">How to define a shared example</h3>
<p>Your index action should respond with 200 success code (OK) and render your index template.</p>
<pre><code>RSpec.shared_examples <span class="hljs-string">"index examples"</span> <span class="hljs-keyword">do</span>   it { expect(subject).to respond_with(:ok) }  it { expect(subject).to render_template(:index) }end
</code></pre><p>Apart from your <code>it</code> blocks — and before and after your hooks — you can add <code>let</code> blocks, context, and describe blocks, which can also be defined inside <code>shared examples</code>.</p>
<p>I personally prefer to keep shared examples simple and concise, and don’t add contexts and let blocks. The <code>shared examples</code> block also accepts parameters, which I’ll cover below.</p>
<h3 id="heading-how-to-use-shared-examples">How to use shared examples</h3>
<p>Adding <code>include_examples "index examples"</code> to your users and posts controller specs includes “index examples” to your tests.</p>
<pre><code># users_controller_spec.rbdescribe <span class="hljs-string">"GET #index"</span> <span class="hljs-keyword">do</span>  before <span class="hljs-keyword">do</span>     <span class="hljs-number">5.</span>times <span class="hljs-keyword">do</span>      FactoryGirl.create(:user)     end    get :index  end  include_examples <span class="hljs-string">"index examples"</span>  it {  expect(assigns(:users)).to match(User.all) }end
</code></pre><pre><code># similarly, <span class="hljs-keyword">in</span> posts_controller_spec.rbdescribe <span class="hljs-string">"GET #index"</span> <span class="hljs-keyword">do</span>  before <span class="hljs-keyword">do</span>     <span class="hljs-number">5.</span>times <span class="hljs-keyword">do</span>      FactoryGirl.create(:post)     end    get :index  end  include_examples <span class="hljs-string">"index examples"</span>  it {  expect(assigns(:posts)).to match(Post.all) }end
</code></pre><p>You can also use <code>it_behaves_like</code> or <code>it_should_behaves_like</code> instead of <code>include_examples</code> in this case. <code>it_behaves_like</code> and <code>it_should_behaves_like</code> are actually aliases, and work in same manner, so they can be used interchangeably. But <code>include_examples</code> and <code>it_behaves_like</code> are different.</p>
<p>As stated in the official documentation:</p>
<ul>
<li><code>include_examples</code> — includes examples in the current context</li>
<li><code>it_behaves_like</code> and <code>it_should_behave_like</code> include the examples in a nested context</li>
</ul>
<h4 id="heading-why-does-this-distinction-matter">Why does this distinction matter?</h4>
<p>RSpec’s documentation gives a proper answer:</p>
<blockquote>
<p><em>When you include parameterized examples in the current context multiple times, you may override previous method definitions and last declaration wins.</em></p>
</blockquote>
<p>So when you face situation where parameterized examples contain methods that conflict with other methods in same context, you can replace <code>include_examples</code> with <code>it_behaves_like</code> method. This will create a nested context and avoid this kind of situations.</p>
<p>Check out the following line in your users controller specs, and posts controller specs:</p>
<pre><code>it { expect(assigns(:users)).to match(User.all) }it { expect(assigns(:posts)).to match(Post.all) }
</code></pre><p>Now your controller specs can be re-factored further by passing parameters to shared example as below:</p>
<pre><code># specs/support/shared_examples/index_examples.rb
</code></pre><pre><code># here assigned_resource and resource <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">are</span> <span class="hljs-title">parameters</span> <span class="hljs-title">passed</span> <span class="hljs-title">to</span> <span class="hljs-title">index</span> <span class="hljs-title">examples</span> <span class="hljs-title">block</span> <span class="hljs-title">RSpec</span>.<span class="hljs-title">shared_examples</span> "<span class="hljs-title">index</span> <span class="hljs-title">examples</span>" <span class="hljs-title">do</span> |<span class="hljs-title">assigned_resource</span>, <span class="hljs-title">resource_class</span>|   <span class="hljs-title">it</span> </span>{ expect(subject).to respond_with(:ok) }  it { expect(subject).to render_template(:index) }  it {  expect(assigns(assigned_resource)).to match(resource_class.all)   }end
</code></pre><p>Now, make following changes to your users and posts controller specs:</p>
<pre><code># users_controller_spec.rbdescribe <span class="hljs-string">"GET #index"</span> <span class="hljs-keyword">do</span>  before <span class="hljs-keyword">do</span>     ...  end  include_examples <span class="hljs-string">"index examples"</span>, :users, User.allend
</code></pre><pre><code># posts_controller_spec.rbdescribe <span class="hljs-string">"GET #index"</span> <span class="hljs-keyword">do</span>  before <span class="hljs-keyword">do</span>     ...  end  include_examples <span class="hljs-string">"index examples"</span>, :posts, Post.allend
</code></pre><p>Now controller specs look clean, less redundant and more importantly, DRY. Furthermore, these index examples can serve as basic structures for designing the index action of other controllers.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>By moving common examples into a separate file, you can eliminate duplication and improve the consistency of your controller actions throughout your application. This is very useful in case of designing APIs, as you can use the existing structure of RSpec tests to design tests and create APIs that adhere to your common response structure.</p>
<p>Mostly, when I work with APIs, I use <code>shared examples</code> to provide me with a common structure to design similar APIs.</p>
<p>Feel free to share how you DRY up your specs by using <code>shared examples</code>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Why Is Test-Driven Development Useful? ]]>
                </title>
                <description>
                    <![CDATA[ By Fagner Brack Tips on how to apply TDD more efficiently, and why it's a valuable technique There's a common pattern we follow when we start a project using TDD. We describe the specifications of what we expect the system to do in the form of a spec... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-test-driven-development-4fb92d56487c/</link>
                <guid isPermaLink="false">66d45eec8812486a37369cc7</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TDD (Test-driven development) ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 08 Dec 2016 10:59:55 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1_HDbOMLg5KeS8tYsbpJYg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Fagner Brack</p>
<h4 id="heading-tips-on-how-to-apply-tdd-more-efficiently-and-why-its-a-valuable-techniquehttpsmediumcomfagnerbrackthe-trick-to-write-better-software-lies-on-the-technique-944015f84ce4">Tips on how to apply TDD more efficiently, and why it's a valuable <a target="_blank" href="https://medium.com/@fagnerbrack/the-trick-to-write-better-software-lies-on-the-technique-944015f84ce4">technique</a></h4>
<p>There's a common pattern we follow when we start a project using TDD. We describe the specifications of what we expect the system to do in the form of a special test. This "special test" can be an end-to-end with the front-end or an integration test that executes an HTTP request to test the back-end.</p>
<p>It's the first test we write. We do it before a single line of code is written. That special test will serve as a guideline to make sure we don't break anything that prevents the regular flow from working. If we don't do that and rely solely on unit tests, there's a chance that, eventually, we will have all tests passing but the server will not be starting or the user won’t be able to do anything on the screen.</p>
<blockquote>
<p>When starting a project using TDD, there's a common pattern to create a special test to make sure we don’t break anything that prevents the regular flow from working.</p>
</blockquote>
<p>After we make that special test pass with a naive implementation (or we can keep it failing if we are using <a target="_blank" href="https://www.agilealliance.org/glossary/atdd/">ATDD</a> to drive the application internals), we start building the units of the system using a similar pattern on a micro level, never breaking any test we created earlier. We describe each unit of the system through a failing test and make it pass with a naive implementation first. Then, we identify <a target="_blank" href="https://medium.com/@fagnerbrack/code-smell-92ebb99a62d0">smells</a> and <a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">refactor</a> it if necessary so that we can keep the cycle going over and over again.</p>
<p>That’s called the <a target="_blank" href="http://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html">Red/Green/Refactor cycle of TDD</a>.</p>
<p>This cycle will drive us to build all the pieces of our application with enough confidence that it will be robust and maintainable. It will also expose problems early if we were to get stuck due to the wrong assumption of how the API is supposed to behave.</p>
<p>There's one important thing we should be careful about: we should <strong>avoid <a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">refactoring</a> code or adding a new test while another test is failing.</strong> If we do that, there's a high chance we will get stuck because of the unnecessary cognitive load of worrying about another rule we have already covered. To prevent that, we need to fix the failing test before starting anything else.</p>
<blockquote>
<p>In TDD, we should <strong>avoid <a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">refactoring</a> code or adding a new test while another test is failing.</strong></p>
</blockquote>
<p>There are circumstances where one would prefer writing tests after writing the code. However, there are some negative effects that come with that approach:</p>
<ul>
<li>We can miss important functionality because it’s harder to know if the coverage matches our expectation.</li>
<li>It can <a target="_blank" href="https://medium.com/@fagnerbrack/mocking-can-lean-to-nondeterministic-tests-4ba8aef977a0">create false positives</a> because we won’t see a failing test first.</li>
<li>It can make us <a target="_blank" href="https://hackernoon.com/how-to-accept-over-engineering-for-what-it-really-is-6fca9a919263">over-engineer</a> the architecture because we won’t have any guidelines to force us to write the minimum amount of code that fits in our most basic requirements.</li>
<li>It's harder to validate if the message for the failing test is clear and pointing to the cause of that failure or not.</li>
</ul>
<p>One thing to keep in mind is that TDD can be posed as a discipline, but <a target="_blank" href="http://blog.cleancoder.com/uncle-bob/2017/03/07/SymmetryBreaking.html">there's no way to create a discipline for writing tests after the production code</a>.</p>
<p>There are <a target="_blank" href="https://8thlight.com/blog/uncle-bob/2014/04/30/When-tdd-does-not-work.html">cases when there's no value in applying TDD or automated testing</a> at all. It's when we're testing some IO layers, support functions for the tests, or things built using a declarative language like HTML or CSS (we can test the visual in CSS, but not the CSS code). However, testing is a fundamental part of the process that ensures a complex piece of functionality satisfies a set of expectations. That alone allows us to be confident enough that each part of the system works as expected.</p>
<blockquote>
<p>There are cases when there's no value in applying TDD or automated testing at all, like when testing IO layers, support functions for the tests, or code written with a declarative language.</p>
</blockquote>
<p>There's a concept called <a target="_blank" href="https://8thlight.com/blog/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html">The Transformation Priority Premise</a>. The <a target="_blank" href="https://en.wikipedia.org/wiki/TL;DR">TL;DR</a> is that there are some transformations we can apply when making the code more generic in the "green" phase of the TDD cycle.</p>
<p>"<a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">Refactor</a>" is when we change the structure of the code without changing its behavior. The Transformations are not called "<a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">refactoring</a>" because they change the structure <strong>and the behavior</strong> of the code to make it more generic.</p>
<p>An example of using the Transformation Priority is when we make a test that forces us from returning a single constant to returning an argument that will contain more than one value. In this case, it's the <strong>constant-&gt;scalar</strong> priority transformation.</p>
<blockquote>
<p><em>So what are these transformations? Perhaps we can make a list of them:</em>  </p>
<p><em><strong>* ({}–&gt;nil)</strong></em> no code at all -&gt; code that employs nil  </p>
<p><em><strong>* (nil-&gt;constant)</strong></em>  </p>
<p><em><strong>* (constant-&gt;constant+)</strong></em> a simple constant to a more complex constant  </p>
<p><em><strong>* (constant-&gt;scalar)</strong></em> replacing a constant with a variable or an argument  </p>
<p><em><strong>* (statement-&gt;statements)</strong></em> adding more unconditional statements.  </p>
<p><em><strong>* (unconditional-&gt;if)</strong></em> splitting the execution path  </p>
<p><em><strong>* (scalar-&gt;array)</strong></em>  </p>
<p><em><strong>* (array-&gt;container)</strong></em>  </p>
<p><em><strong>* (statement-&gt;recursion)</strong></em>  </p>
<p><em><strong>* (if-&gt;while)</strong></em>  </p>
<p><em><strong>* (expression-&gt;function)</strong></em> replacing an expression with a function or algorithm  </p>
<p><em><strong>* (variable-&gt;assignment)</strong></em> replacing the value of a variable.  </p>
<p><em>There are likely others.</em>  </p>
<p><em>— Excerpt from <a target="_blank" href="https://8thlight.com/blog/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html">The Transformation Priority Premise</a> article</em></p>
<p>In TDD, The Transformation Priority Premise can give us a guideline for the "green" phase.</p>
</blockquote>
<p><a target="_blank" href="https://medium.com/@fagnerbrack/the-trick-to-write-better-software-lies-on-the-technique-944015f84ce4">Writing correct software is hard</a>. TDD is a common pattern where we use the tests to help driving the implementation of our system while retaining a huge percentage of test coverage. However, it's not a <a target="_blank" href="https://medium.com/@fagnerbrack/how-to-reject-the-belief-on-the-silver-bullet-1d86b686acbb">Silver Bullet</a>.</p>
<p>If we are using TDD, we should avoid <a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">refactoring</a> the code when the tests are failing. To make it pass in the "green" phase, we use the Transformation Priority Premise to guide us in the most naive implementation approach we can take before <a target="_blank" href="https://medium.com/@fagnerbrack/how-to-refactor-a-public-interface-317ed18d38a3">refactoring</a>.</p>
<p>In comparison with other ways of writing tests, TDD can take more time in the beginning. However, as with every new skill, with enough practice we will reach a plateau, and the time it takes to apply TDD will be no different than the time it would take to write tests in a traditional way.</p>
<p>The difference now is that your software will be less likely to behave in a way you didn't expect.</p>
<p>And for all practical means, that's no different than 100% test coverage.</p>
<p>Thanks for reading. If you have some feedback, reach out to me on <a target="_blank" href="https://twitter.com/FagnerBrack">Twitter</a>, <a target="_blank" href="https://www.facebook.com/fagner.brack">Facebook</a> or <a target="_blank" href="http://github.com/FagnerMartinsBrack">Github</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
