<?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[ Quality Assurance - 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[ Quality Assurance - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 20 Sep 2026 21:09:22 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/quality-assurance/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Automate Your Tests in Express Using Vitest ]]>
                </title>
                <description>
                    <![CDATA[ Thinking through API logic while constantly switching tabs to test application integration can be overwhelming and time-consuming. Well, you can save your time and energy by writing tests for your app ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-automate-your-tests-in-express-using-vitest/</link>
                <guid isPermaLink="false">6a91aa2c85465e213741c4de</guid>
                
                    <category>
                        <![CDATA[ vitest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Integration Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mocking ai ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API mocking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mocking api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose-mocking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ qa testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Supertest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mockingoose ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ jabo Landry ]]>
                </dc:creator>
                <pubDate>Fri, 28 Aug 2026 15:33:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/098eaca4-3334-4a81-b6f6-ad0b167eee44.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Thinking through API logic while constantly switching tabs to test application integration can be overwhelming and time-consuming.</p>
<p>Well, you can save your time and energy by writing tests for your application that run whenever you add a new feature, all without leaving your IDE during development. This will help you be confident that each feature works as expected.</p>
<p>In this guide, I'll help you build confidence through code: you'll learn how to validate APIs with tests first, then confirm the results in Postman or any other API testing tool.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p><strong>Node.js &amp; Express basics:</strong> You should have a working knowledge of Node.js and Express (or a similar library like <code>fastify</code>), including how to build and run a simple API.</p>
</li>
<li><p><strong>Working knowledge of TypeScript:</strong> The code snippets in this guide are written using TypeScript, so you should have a solid understanding of TypeScript basics.</p>
</li>
<li><p><strong>Basic familiarity with MongoDB:</strong> Helpful but not required. The examples in this guide use MongoDB for demonstration purposes, but the underlying logic applies to any database or data layer. Only the tooling differs.</p>
</li>
<li><p><strong>Hands-on API experience:</strong> Prior experience writing at least one backend API with Express will help you follow along more effectively.</p>
</li>
<li><p><strong>Curiosity and motivation:</strong> A willingness to deepen your backend skills by learning how to write and run tests for your APIs.</p>
</li>
<li><p><strong>Environment setup:</strong> Node.js version <strong>20 or higher</strong> installed on your machine.</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-testing-concept">Testing Concept</a></p>
</li>
<li><p><a href="#heading-unit-testing">Unit testing</a></p>
</li>
<li><p><a href="#heading-comparison-between-unit-and-integration-tests">Comparison between unit and integration tests</a></p>
</li>
<li><p><a href="#heading-summary">Summary</a></p>
</li>
</ul>
<p>You can find all the code snippets used in this guide in this <a href="https://github.com/jabo-arnold-landry/testing-lesson">Git repository</a>. Each example has its own branch, and they're combined into a main branch if you want a full example version. Please consider starring the repository if you find it helpful.</p>
<h2 id="heading-key-testing-concepts">Key Testing Concepts</h2>
<p>Testing helps you build confidence in your codebase. You wrie code that tests other code in your application, or code that checks if a function or feature behaves the way that it should.</p>
<p>In this guide, we'll cover two types of testing:</p>
<ul>
<li><p><strong>Unit testing</strong>: This is the most basic type of testing and, in my opinion, the easiest. You test a single piece of code in isolation to see how it behaves.</p>
</li>
<li><p><strong>Integration testing</strong>: This approach is used to test how different parts of the application are integrated to make sure they're working together as intended.</p>
</li>
</ul>
<h3 id="heading-key-testing-terms">Key Testing Terms</h3>
<p>Throughout this guide, I'll be using some technical terms are related to testing which I want to explain up front:</p>
<ul>
<li><p><strong>Mocking</strong>: mocking is a technique used to make a fake implementation of a real function call.</p>
</li>
<li><p><strong>Spying</strong>: spying is a way of inspecting a function to see, for example, if the function is called with a certain type of argument or how many times it's been called.</p>
</li>
<li><p><strong>Assertion</strong>: assertions check to see if the output you're getting matches the expected output.</p>
</li>
</ul>
<p>Alright now that we have that covered, let's go over some basics of testing so you have the best practices down before we start writing tests.</p>
<h3 id="heading-how-to-name-a-test-file">How to Name a Test File</h3>
<p>Make sure your test files follow one of these naming conventions:</p>
<ul>
<li><p><code>filename.test.ts</code></p>
</li>
<li><p><code>filename.spec.ts</code></p>
</li>
<li><p><code>filename.test.js</code></p>
</li>
<li><p><code>filename.spec.js</code></p>
</li>
</ul>
<p>Both the <code>spec</code> and <code>test</code> keyword in a file name makes it possible to run the test file. They also help testing frameworks run the right file.</p>
<p>You can choose either the TypeScript or JavaScript extension on a file based on which language you're using to write the test. For this guide I'm using TypeScript so I'll be using the TypeScript (<code>.ts</code>) test file version.</p>
<h3 id="heading-parts-of-a-testing-file">Parts of a Testing File</h3>
<p>Typically, a test file will have four main parts that you should be familiar with, which are:</p>
<ul>
<li><p><code>describe</code>: Used to describe which test you're going to write.</p>
</li>
<li><p><code>it</code>: Used to specify a condition that a function must pass when tested against.</p>
</li>
<li><p><code>expect</code>: Used to determine what type of results you're expecting when you call a function that's being tested</p>
</li>
<li><p><code>matchers</code>: These are different method available on the <code>expect</code> keyword that we use to evaluate if the function we're testing returns a value that meets the expected data or value.</p>
</li>
</ul>
<p>Example of a test file:</p>
<pre><code class="language-typescript">import { describe, it, expect } from "vitest";
import validateEmail from "../utils/email-validation";

describe("email validation test suites", () =&gt; {
  it("must define email validation function", () =&gt; {
    expect(validateEmail).toBeDefined();
  });
});
</code></pre>
<p>The above snippet tests if the <code>validateEmail</code> function is defined.</p>
<p>In this test file:</p>
<ul>
<li><p>We use <code>describe</code> to specify the description of the test. <code>describe</code> receives a string description of the test and a function to handle different test cases.</p>
</li>
<li><p>The <code>it</code> keyword specifies and defines a test for a function you're testing, <code>it</code> receives a string describing a specific test description and a callback function to execute and handle test assertion.</p>
</li>
<li><p>Then <code>expect</code> uses the function return type to check if it matches a specific condition through the <code>toBeDefined</code> matcher method.</p>
</li>
</ul>
<h3 id="heading-list-of-matchers">List of Matchers:</h3>
<p>There are many matchers available to you. Below are a few of them:</p>
<ul>
<li><p><code>toBe</code>: compares the passed-in value to see if it matches the function's returned value. It's used on primitive data types like strings, numbers, and so on.</p>
</li>
<li><p><code>toEqual</code>: compares the passed-in value to see if it matches the function's returned value. It's used on non-primitive data types like objects, arrays, and so on.</p>
</li>
<li><p><code>toThrow</code>: used on a function that threw an error to check if the function threw expected error object or instance.</p>
</li>
<li><p><code>toBeCalledWith</code>: used to check if a function is called with a given parameter.</p>
</li>
<li><p><code>toBecalledOnce</code>: used to check if a function is called only once.</p>
</li>
<li><p><code>toBeDefined</code>: used to check if a function is defined.</p>
</li>
<li><p><code>toBeUndefined</code>: used to check if a function returns an undefined value.</p>
</li>
<li><p><code>toBeTruthy</code>: used to check if a function returns a true Boolean value.</p>
</li>
<li><p><code>toBeFalsy</code>: used to check if a function returns a false Boolean value.</p>
</li>
</ul>
<p>These are few of the many matchers out there.</p>
<h3 id="heading-vitest-installation">Vitest Installation</h3>
<p>Now that you know some testing basics, we can get into the actual tests. We'll start by installing <code>vitest</code>, the framework that we'll use to run and write tests for our application.</p>
<p>You can choose your preferred package manager to use to install <code>vitest</code> from the list below:</p>
<pre><code class="language-shell">pnpm add -D vitest # for pnpm package manager
npm install -D vitest # for npm package manager
yarn add -D vitest # for yarn package manager
bun add -D vitest # for bun package manager
</code></pre>
<h2 id="heading-unit-testing">Unit Testing</h2>
<p>A unit test focuses on testing a small piece of code in isolation in your application. A simple example could be if you have a function that adds contact info to a database. For the test, you could check if the email is valid before adding the contact to the database.</p>
<p>Let's start by testing a simple email validation function so you can get comfortable with how unit tests works and how to write one:</p>
<pre><code class="language-typescript">export default function validateEmail(email: string) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

  if (regex.test(email)) {
    return true;
  } else {
    throw new Error("Invalid email format");
  }
}
</code></pre>
<p>The above snippet exports a function that receives an email and then uses regex to validate if the email is valid. It throws an error if the email is invalid.</p>
<h3 id="heading-tests-for-the-validateemail-function">Tests for the <code>validateEmail</code> Function</h3>
<p>Let's start by checking if <code>validateEmail</code> returns true for correct emails:</p>
<pre><code class="language-typescript">import { describe, it, expect } from "vitest";
import validateEmail from "../utils/email-validation";

describe("email validation test suites", () =&gt; {

  it("returns true for valid email", () =&gt; {
    const sampleEmail = "arnoldjabo@gmail.com";
    expect(validateEmail(sampleEmail)).toBeTruthy();
  });

});
</code></pre>
<p>In the above test, we're creating a variable <code>sampleEmail</code> to be used as a sample email in the <code>validateEmail</code> function. Save this and then run <code>npx vitest</code> in your terminal. You should see a terminal with the results of your test. It should look like the below screenshot:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69c7bcff7cf27065100ae8be/84af7e2b-8344-49c8-a744-35d64ee2a1c0.png" alt="passed tests in vitest terminal" style="display: block;" width="600" height="400" loading="lazy">

<p>When you run tests, Vitest shows the list of test files you're testing, how many tests were executed, and how many passed and failed tests you have.</p>
<p>Let's create another test that detects an invalid email:</p>
<pre><code class="language-typescript">import { describe, it, expect } from "vitest";
import validateEmail from "../utils/email-validation";

describe("email validation test suites", () =&gt; {

    it("throws error for invalid email", () =&gt; {
    const sampleEmail = "verymasd.com";
    const invalidEmailResults = () =&gt; validateEmail(sampleEmail);
    expect(invalidEmailResults).toThrow("Invalid email format");
  });

});
</code></pre>
<p>For functions that throw errors, you need to wrap them inside another function to prevent them from stopping the test before the test reaches the assertion or <code>expect</code> section.</p>
<p>In our example above, the <code>validateEmail</code> function is wrapped inside another function which will hold whatever the error <code>validateEmail</code> throws is. It then assigns it to the <code>invalidEmailResults</code> variable. Next we use the <code>toThrow</code> matcher on the <code>expect</code> assertion to match a type of error <code>validateEmail</code> expects to be thrown for an invalid email.</p>
<p>If your run the test, you'll have two passed tests now:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69c7bcff7cf27065100ae8be/521702d7-073b-44e7-90dc-9a30b664b81d.png" alt="Passed test for invalid email that throws an error for an invalid email" style="display: block;" width="600" height="400" loading="lazy">

<p>If you didn't wrap the <code>validateEmail</code> function inside another function when it throws an error, you'll see something like this when you run the test:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69c7bcff7cf27065100ae8be/693fec20-7f56-42ea-be18-4caa5cba3dac.png" alt="The error message you would receive inside the test terminal if you didn't wrap a function that throws an error inside another function." style="display: block;" width="600" height="400" loading="lazy">

<p>As you can see, the error fires before reaching the test final assertion. So when you have a function that throws errors, remember to wrap your function inside another function to avoid throwing errors mid-test.</p>
<p><strong>Tip</strong>: When writing unit tests, focus on the expected input and output of a function. You don't have to worry or need to think about the implementation of the function: the input and output are the key elements here.</p>
<h3 id="heading-testing-api-calls">Testing API Calls</h3>
<p>By now you should understand how a unit test works. So next, let's see how you can unit test an API that makes a call to a database.</p>
<pre><code class="language-typescript">import Contacts from "../../schema/contactList";
import { Request, Response } from "express";
import validateEmail from "../../utils/email-validation";

async function addContacts(req: Request, res: Response) {
  const { contactName, phoneNumber, email } = req.body;
  validateEmail(email);

  const contact = await Contacts.create({ contactName, phoneNumber, email });

  return res.status(201).json({ message: `successfully created ${contact.contactName}` });
}

export default addContacts;
</code></pre>
<p>In the code snippet above, we have a function that creates a contact with the database. It also validates if the passed email is valid.</p>
<p>In this example, we're using mongo DB for the database and Mongoose for connecting the codebase with our mongo DB instance.</p>
<p>Unit tests for non-pure functions (that is, functions that are dependent on external services, like making API calls or calling other functions) are tested a bit differently.</p>
<p>For these cases, you create a mock or fake version of the original function that makes a call to the external service and then define its behavior to match the expected return value that you'd have if you used its real version.</p>
<p>We'll start by mocking the implementation of the email validation function. This will help solidify the understanding on how mocking works in unit testing and testing in general.</p>
<p><strong>Note</strong>: mocking the <code>validateEmail</code> function isn't that important because it doesn't make a big difference from using the email validation function directly here. But for learning purposes, we'll mock it to help you understand how it works.</p>
<p>When mocking the modules import, we use the <code>vi.mock</code> function which helps transform the imports of a given module into mocks or fake versions of the real ones.</p>
<pre><code class="language-typescript">vi.mock(filepath,callback);
</code></pre>
<p><code>vi.mock</code> receives two arguments: the file path location of the module you want to mock, and a callback function called a factory function which we'll use to transform the module imports into mocks.</p>
<p>Let's start by mocking the <code>validateEmail</code> path and creating a factory function to transform the module into mocks:</p>
<pre><code class="language-typescript">vi.mock("../utils/email-validation", () =&gt; {
  return { default: vi.fn()};
});
import validateEmail from "../utils/email-validation";
</code></pre>
<p>In the callback function (factory function), we then return an object of the exported module, with a key of <strong>default</strong> and a value of <code>vi.fn</code>. For function mocking we use <code>vi.fn()</code> which automatically replaces the function's return value with <code>undefined</code>.</p>
<p>We use default as a key because the <code>validateEmail</code> function is exported as a default export. If it was a named export, we would have used the actual export name instead of default in the return object.</p>
<pre><code class="language-typescript">vi.mock("../utils/email-validation", () =&gt; {
  return { validateEmail: vi.fn() };
});
import { validateEmail } from "../utils/email-validation";
</code></pre>
<p>Always import your module after the mock module operation to avoid using the real module.</p>
<p>There are methods on <code>vi.fn()</code> that help define the implementation and behaviors of the mocked function. Some of these methods include:</p>
<ul>
<li><p><code>mockReturnValue</code>: Used to define a return value for a mocked function</p>
</li>
<li><p><code>mockRejectsValue</code>: Used for promise-based functions to define the error the function will return.</p>
</li>
<li><p><code>mockResolveValue</code>: Used for promise-based functions to define the data the function will return.</p>
</li>
<li><p><code>mockImplementation</code>: Used to define a new function behavior of a mocked function.</p>
</li>
<li><p><code>mockReturnThis</code>: Used to return the actual instance of a function you're mocking.</p>
</li>
</ul>
<p>These are the methods that you'll likely use most of the time when defining mock implementation and setting mock return value. Just keep in mind that there are many others.</p>
<p>Here, for <code>emailValidate</code>, we'll be using the <code>mockReturnValue</code> and <code>mockImplementation</code> methods.</p>
<p>Let's use <code>mockReturnValue</code> to make the validateEmail function return true by default, assuming the email will be formatted correctly:</p>
<pre><code class="language-typescript">vi.mock("../utils/email-validation", () =&gt; {
  return { default: vi.fn().mockReturnValue(true) };
});
import validateEmail from "../utils/email-validation";
</code></pre>
<p>We define a mock function with <code>vi.fn</code> and then chain on the <code>mockReturnValue(true)</code> to change the mock function default return value (undefined) to true in our case.</p>
<h3 id="heading-defining-the-mocking-implementation">Defining the Mocking Implementation</h3>
<p>You can do a lot with a mocked function, like defining a new implementation for the mocked function that replaces existing logic in the original function.</p>
<p>Let's create a test suite with a fake email that throws an error when you pass the wrong email while creating contacts.</p>
<pre><code class="language-typescript">import { describe, expect, it, vi } from "vitest";
import mockinggoose from "mockingoose";
import Contacts from "../schema/contactList";
import addContacts from "../src/controllers/add-contacts.controller";

import { type Response, type Request } from "express";

vi.mock("../utils/email-validation", () =&gt; {
  return { default: vi.fn().mockReturnValue(true) };
});

import validateEmail from "../utils/email-validation";

const fakeContact = {
  contactName: "arnold",
  phoneNumber: 798600102,
  email: "arnoldjabo@gmail.com",
};

describe("Add contacts to the database", async () =&gt; {
  it("throws error for the wrong email address", async () =&gt; {
    const req = {
      body: { ...fakeContact, email: "fakemail" },
    } as Request;  

    const res = {
      status: vi.fn().mockReturnThis(),
      json: vi.fn(),
    } as any as Response;

    (validateEmail as ReturnType&lt;typeof vi.fn&gt;).mockImplementation(() =&gt; {
      throw new Error("invalid email!");
    });
 
    await expect(addContacts(req, res)).rejects.toThrow();
  });
});
</code></pre>
<p>In the snippet above, we're mocking or creating a fake request object that's cast as request type of <code>express</code>. We do the same with the response object – but the difference here is that with response we're also creating mocks for common methods that you'd use on an Express response (which are status and a <code>json</code> object).</p>
<p>We then turn the return type of the <code>validateEmail</code> function into the vitest mocking function type to avoid TypeScript warnings. Then we use the <code>mockImplementation</code> method to throw a new error inside <code>validateEmail</code>.</p>
<p>The assertion works differently because now we're throwing a promise-based error. We use <code>rejects</code> on the assertion and then chain on another matcher that stimulates which type of error the function will throw.</p>
<p><strong>Tip:</strong> when working with TypeScript, the response object can't be cast like we did on the request object because the response object is much stricter than request. So you'll first need to cast it as any and then cast back to the response object. That way you avoid the TypeScript warning while still keeping the type in play for your test code.</p>
<h3 id="heading-mocking-a-mongoose-model">Mocking a Mongoose Model</h3>
<p>With unit tests, we don't want to save test data to a real database. Instead we can fake the implementation of the service that calls the database service – in our case, we can use the <code>create</code> method from Mongoose. It'll save the record to a Mongo database. We can then define what it should return on success (and it should look identical to what it would return if we were using a real database).</p>
<p>We'll start by installing a library for mocking a Mongoose model called <code>mockingoose</code>:</p>
<pre><code class="language-shell">pnpm add -D mockingoose # for pnpm package manager
npm install -D mockingoose # for npm package manager
yarn add -D mockingoose # for yarn package manager
bun add -D mockingoose # for bun package manager
</code></pre>
<p>After installation we'll create a mock for our contacts model:</p>
<pre><code class="language-typescript">import { describe, expect, it, vi } from "vitest";
import mockinggoose from "mockingoose";
import Contacts from "../schema/contactList";

const fakeContact = {
  contactName: "arnold",
  phoneNumber: 798600102,
  email: "arnoldjabo@gmail.com",
};

describe("Add contacts to the database", async () =&gt; {
  it("successfully create a new contact to the database", async () =&gt; {
    mockinggoose(Contacts).toReturn(fakeContact, "save");
  });

});
</code></pre>
<p>To mock a Mongoose model, we call the <code>mockinggoose()</code> function and pass the model to mock. Then we use the <code>toReturn</code> matcher to describe what it should return, <code>toReturn</code> matcher expects two arguments.</p>
<p>Those arguments are a fake dataset for the model and a Mongo method that we'll use to work with the data. For our example we'll use <code>save</code> because we're creating records in the document.</p>
<h3 id="heading-unit-testing-the-api">Unit Testing the API</h3>
<p>We can start by writing the first test for the add contact API call like this:</p>
<pre><code class="language-typescript">import { describe, expect, it, vi } from "vitest";
import mockinggoose from "mockingoose";
import Contacts from "../schema/contactList";
import addContacts from "../src/controllers/add-contacts.controller";
import { type Response, type Request } from "express";

vi.mock("../utils/email-validation", () =&gt; {
  return { default: vi.fn().mockReturnValue(true) };
});

import validateEmail from "../utils/email-validation";

const fakeContact = {
  contactName: "arnold",
  phoneNumber: 798600102,
  email: "arnoldjabo@gmail.com",
};

describe("Add contacts to the database", async () =&gt; {
  it("successfully create a new contact to the database", async () =&gt; {
    mockinggoose(Contacts).toReturn(fakeContact, "save");

    const req = {
      body: fakeContact,
    } as Request;

    const res = {
      status: vi.fn().mockReturnThis(),
      json: vi.fn(),
    } as any as Response;

    await addContacts(req, res);
    expect(res.status).toHaveBeenCalledWith(201);
    expect(res.json).toHaveBeenCalledWith({
      message: `successfully created ${fakeContact.contactName}`,
    });
  });
 });
</code></pre>
<p>For this test assertion, we're using different matchers called <strong>spies</strong>. These are used on a function to inspect how many times it's been called or which parameters were used to call it (and so on).</p>
<p>Here we're expecting the status function of response to be called with a status of 201 as its argument. Then the JSON object is called with a message argument that we're using to send out the response.</p>
<h2 id="heading-integration-tests">Integration Tests</h2>
<p>Integration tests test the communication and integration of different parts of an application. For example, they might check if your database integrates well with the function that makes the API call to the database.</p>
<p>Unlike unit tests (where we don't need to have our test making API calls), with integration tests we're testing if parts of the application integrate together and works as expected. We don't need to mock anything, because we want to make sure that we're successfully sending a request to the backend and connecting to the database.</p>
<h3 id="heading-creating-integration-test-data-storage">Creating Integration Test Data Storage</h3>
<p>When you're running integration tests, there are two ways to create a testing environment that acts as a database. They include:</p>
<ul>
<li><p>Creating a duplicate schema of your real database and using the copy as a testing database environment. Whenever you're running tests, you point your database connectivity to the test DB.</p>
</li>
<li><p>Creating in-memory database storage. This approach doesn't require you to have two separate schemas (one for testing and another for production). Instead you construct the same schema shape in your codebase memory and use it as your testing environment.</p>
</li>
</ul>
<p>Using the first approach is complicated because you have to set up and configure which database to use for which environment. But for the second approach, you can just set up the right schema structure as the original schema and use it for testing without needing to configure it in the database and remove it after use.</p>
<p>For Mongo DB there's a package that simplifies the in-memory storage option for us called <code>mongodb-memory-server</code>. It deletes all the data that was used for testing after the tests have finished running.</p>
<h3 id="heading-how-to-set-up-the-environment-for-the-integration-tests">How to Set Up the Environment for the Integration Tests</h3>
<p>You'll need to install:</p>
<ul>
<li><p><code>supertest</code>: a package that helps you make API calls/requests and returns back the response when testing.</p>
</li>
<li><p><code>mongodb-memory-server</code>: a package that makes in memory database storage for testing data.</p>
</li>
</ul>
<pre><code class="language-shell"># command for pnpm package manager
pnpm add -D mongodb-memory-server supertest @types/supertest

# command for npm package manager
npm install --save-dev mongodb-memory-server supertest @types/supertest

# command for yarn package manager
yarn add --dev mongodb-memory-server supertest @types/supertest

# command for bun package manager
bun add -d mongodb-memory-server supertest @types/supertest
</code></pre>
<p>Before moving on, we need to change the setup of our server entry file.</p>
<p>If you've been using Express with Node or any other framework, you may be familiar with the following type of setup for the server entry file where everything is added into a single file:</p>
<pre><code class="language-typescript">import express from "express";
import { loadEnvFile } from "node:process";
import connectToDB from "../config/dbConfig";
import addContacts from "./controllers/add-contacts.controller";

const app = express();
loadEnvFile();
async function dbConnection() {
  await connectToDB();
}
dbConnection();

app.use(express.json());
app.post("/add-contacts", addContacts);
app.listen(5000, () =&gt; console.log("the server successfully connected"));
</code></pre>
<p>This setup works fine and it's valid in certain cases. But when working with integration tests, it can be problematic. This is because in integration tests, we'll need an instance of Express to use when making the request. If we export the <code>app</code> variable here inside the main file when we make a request while testing, the production DB connection will conflict with the testing DB connection. This'll cause the tests to stop working.</p>
<p>The solution here is create another file, define an Express instance, and export it. Then we'll use the exported Express instance in the server to start a server. The setup looks like this:</p>
<p><code>app.ts</code></p>
<pre><code class="language-typescript">import express from "express";
import addContacts from "./controllers/add-contacts.controller";

const app = express()

app.use(express.json())
app.post("/add-contacts", addContacts);

export default app;
</code></pre>
<p>Then the main file <code>server.ts</code> or <code>main.ts</code> uses the <code>app</code> variable like this:</p>
<pre><code class="language-typescript">import { loadEnvFile } from "node:process";
import connectToDB from "../config/dbConfig";
import app from "./app";

loadEnvFile();

async function bootsrap() {
  await connectToDB();
  app.listen(5000, () =&gt; console.log("the server successfully connected"));
}
bootsrap();
</code></pre>
<p>We're importing the Express instance from the <code>app</code> file and then using the <code>bootstrap()</code> function to set up the database and start the server. With this in place, we can start writing integration tests for the <code>addContact</code> module.</p>
<h3 id="heading-how-to-write-the-integration-tests">How to Write the Integration Tests</h3>
<p><strong>Tip</strong>: With integration test(s) you can name your file like <code>filename.integration.test.ts</code> this is the most commonly used naming convention for integration tests, but it is not mandatory it just a naming convention.</p>
<p>You first need to set up the database testing data storage using the <code>mongoose</code> and <code>mongdb-memory-server</code> packages and the Express instance for making requests.</p>
<pre><code class="language-typescript">import { afterAll, beforeAll, describe, expect, it } from "vitest";

import { MongoMemoryServer } from "mongodb-memory-server";
import mongoose from "mongoose";
import app from "../src/app";


describe("intergration test setup for add contact api", () =&gt; {
  let mongoServer: MongoMemoryServer;
  let server: any;

  beforeAll(async () =&gt; {
    mongoServer = await MongoMemoryServer.create();
    const uri = mongoServer.getUri();
    await mongoose.connect(uri);
    server = app.listen(0);
  });

  afterAll(async () =&gt; {
    mongoServer.stop();
    mongoose.disconnect();
    server.close();
  });
});
</code></pre>
<p>The <code>beforeAll</code> and <code>afterAll</code> functions are <code>vitest</code> functions. <code>beforeAll</code> runs before any test starts executing and <code>afterAll</code> will run after all tests are done executing.</p>
<p>In the test, we set up the database and Express instance before any test runs.</p>
<p>First, we created the <code>mongoServer</code> variable. Then, inside the <code>beforeAll</code> block, we initialize it with <code>MongoMemoryServer.create</code> to create an in-memory database for testing data storage. We get the connection string using the <code>uri</code> variable using the <code>getUri</code> method. Finally we use Mongoose to connect to the generated in-memory connection string.</p>
<p>The server variable is assigned to the Express instance listening to port 0, but you can use any port number of your choice – it's just for demonstration purposes. This creates an Express instance for our testing environment.</p>
<p>In <code>afterAll</code>, after all tests have finished executing, we close the server and in-memory DB and then also disconnect our Mongoose instance.</p>
<p>Within the same <code>describe</code> block, we then add the test description and assertion (same as we did in unit testing):</p>
<pre><code class="language-typescript">import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { MongoMemoryServer } from "mongodb-memory-server";
import mongoose from "mongoose";
import app from "../src/app";
import request from "supertest";
import Contacts from "../schema/contactList";

describe("intergration test for add contact api", () =&gt; {
  /*
    Here we do server setup and database in memory setup that was discussed,
    in the previous snippets for setting up integration data storage testing environment 
   */
  const fakeContact = {
    contactName: "arnold",
    phoneNumber: 798600102,
    email: "arnoldjabo@gmail.com",
  };

  describe("POST /add-contacts", () =&gt; {
    it("creates a new record to the database", async () =&gt; {
      const response = await request(app)
        .post("/add-contacts")
        .send(fakeContact);

       const contactList = await Contacts.findOne({
        email: "arnoldjabo@gmail.com",
      })!;
      expect(contactList?.email).toBe("arnoldjabo@gmail.com");
      console.log(contactList);

      expect(response.status).toBe(201);
      expect(response.body).toEqual({
        message: `successfully created ${fakeContact.contactName}`,
      });
    });
  });
});
</code></pre>
<p>Here in the test file, we're describing the test as a post method test for the add-contact endpoint. Then we test if it adds data to the database.</p>
<p>Within the <code>it</code> body, we use <code>request</code> from <code>supertest</code> to make a request to the server we've created. We also chain on an HTTP method with the endpoint we want to test.</p>
<p>For methods that send data to the backend like POST, PATCH, or PUT, we use the <code>send</code>() method on <code>request</code> to add an object of the data that we're sending.</p>
<p>We'll use the response to assert what the response could look like. For example, we're expecting the server to give a status code of 201 on successful data entry and a JSON object with a message property that confirms that it has added a contact.</p>
<p>We're using an assertion to check if the response's status matches what we expect, as well as if the response body matches the expected message we should be getting.</p>
<p>To test if the data are really being added to the database, I've added <code>contactList</code> to get the contact we just added by finding it by email. Then we log the <code>contactList</code> to the console to show how in-memory works. It's pretty much the same as a real Mongo DB instance. If we were to run the tests, we would have something that looks like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69c7bcff7cf27065100ae8be/e20082ae-0d06-48e2-b40b-8c66846c7ed4.png" alt="Out-put for integration test with the console log showing how that stored using in memory database looks like when printed to the screen." style="display: block;" width="600" height="400" loading="lazy">

<p>You can see from the console the in-memory stores and retrieves data as a regular Mongo database does.</p>
<h2 id="heading-when-to-use-unit-vs-integration-tests">When to Use Unit vs Integration Tests</h2>
<p>So when do you use each type of test?</p>
<p>Use unit tests when you have pure functions like the email validation example we had earlier.</p>
<p>And use Integration tests for functions that makes external API calls that are dependent on external service like database calls to avoid mocking every function that you're importing.</p>
<h2 id="heading-summary">Summary</h2>
<p>This guide explains how two types of testing work: unit tests and integration tests.</p>
<p>Unit tests are code that tests specific pieces of your codebase in isolation, and are best for pure functions. Integration test are code that tests successful integration and communication between parts of your application, and they're best for non-pure functions.</p>
<p>If you found the article helpful, you can <a href="https://buymeacoffee.com/jabo1200">buy me coffee</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test Conversational AI: A Practical Guide for QA Engineers ]]>
                </title>
                <description>
                    <![CDATA[ When I first started learning about conversational AI testing, one question kept bothering me: Where is the expected result? Coming from traditional software testing, I was used to a familiar pattern. ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-test-conversational-ai-practical-guide-for-qa-engineers/</link>
                <guid isPermaLink="false">6a8c5708cc6859117f26da4f</guid>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ai testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ QA engineering ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ GAYATHRI BOLINENI ]]>
                </dc:creator>
                <pubDate>Mon, 24 Aug 2026 14:36:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/61896a64-69bb-46cb-87dd-0076c4aa1b50.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When I first started learning about conversational AI testing, one question kept bothering me: <strong>Where is the expected result?</strong></p>
<p>Coming from traditional software testing, I was used to a familiar pattern.</p>
<p>A requirement tells us what the system should do. We create a test case, provide an input, define an expected result, execute the test, and compare the actual result with what we expected.</p>
<p>For example:</p>
<table>
<thead>
<tr>
<th>Test</th>
<th>Input</th>
<th>Expected Result</th>
</tr>
</thead>
<tbody><tr>
<td>Valid login</td>
<td>Correct username and password</td>
<td>User logs in</td>
</tr>
<tr>
<td>Invalid login</td>
<td>Incorrect password</td>
<td>Error message displayed</td>
</tr>
<tr>
<td>API request</td>
<td>Valid request payload</td>
<td>HTTP 200 with expected response</td>
</tr>
</tbody></table>
<p>Then I started learning conversational AI. Suddenly, the same approach didn't fit quite as neatly.</p>
<p>If I ask an AI agent "How can I reset my password?", it might answer, "You can reset your password using the Forgot Password option on the login page."</p>
<p>Ask the same question again and it might say: "Select Forgot Password from the sign-in screen and follow the instructions sent to your registered email."</p>
<p>The wording is different, but both responses may be perfectly acceptable. So how do we test something when the exact response can change?</p>
<p>That question changed the way I approached conversational AI testing.</p>
<p>In this article, I'll walk through the testing areas I found most important while learning how conversational systems behave, and show how traditional QA techniques can be adapted for AI agents.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-1-start-with-intent-not-exact-wording">1. Start With Intent, Not Exact Wording</a></p>
</li>
<li><p><a href="#heading-2-dont-use-exact-text-matching-for-every-response">2. Don't Use Exact Text Matching for Every Response</a></p>
</li>
<li><p><a href="#heading-3-evaluate-response-quality-across-multiple-dimensions">3. Evaluate Response Quality Across Multiple Dimensions</a></p>
</li>
<li><p><a href="#heading-4-test-the-conversation-not-just-the-response">4. Test the Conversation, Not Just the Response</a></p>
</li>
<li><p><a href="#heading-5-test-whether-the-ai-can-handle-corrections">5. Test Whether the AI Can Handle Corrections</a></p>
</li>
<li><p><a href="#heading-6-test-ambiguity">6. Test Ambiguity</a></p>
</li>
<li><p><a href="#heading-7-test-the-knowledge-behind-the-answer">7. Test the Knowledge Behind the Answer</a></p>
</li>
<li><p><a href="#heading-8-test-for-hallucinations">8. Test for Hallucinations</a></p>
</li>
<li><p><a href="#heading-9-test-fallback-behavior">9. Test Fallback Behavior</a></p>
</li>
<li><p><a href="#heading-10-test-human-escalation">10. Test Human Escalation</a></p>
</li>
<li><p><a href="#heading-11-test-integrations-like-you-would-in-any-other-application">11. Test Integrations Like You Would in Any Other Application</a></p>
</li>
<li><p><a href="#heading-12-build-a-golden-dataset">12. Build a Golden Dataset</a></p>
</li>
<li><p><a href="#heading-13-dont-only-measure-pass-rate">13. Don't Only Measure Pass Rate</a></p>
</li>
<li><p><a href="#heading-14-create-risk-based-conversational-tests">14. Create Risk-Based Conversational Tests</a></p>
</li>
<li><p><a href="#heading-15-a-practical-conversational-ai-test-strategy">15. A Practical Conversational AI Test Strategy</a></p>
</li>
<li><p><a href="#heading-what-traditional-qa-engineers-already-bring-to-ai-testing">What Traditional QA Engineers Already Bring to AI Testing</a></p>
</li>
<li><p><a href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-1-start-with-intent-not-exact-wording">1. Start With Intent, Not Exact Wording</h2>
<p>Consider these three messages:</p>
<ol>
<li><p>"How do I reset my password?"</p>
</li>
<li><p>"I can't access my account."</p>
</li>
<li><p>"Forgot password."</p>
</li>
</ol>
<p>They look different. But depending on the application, they may all represent the same underlying user goal:</p>
<p><strong>PASSWORD_RESET</strong></p>
<p>In conversational AI, the sentence a user types is often called an <strong>utterance</strong>, while the goal behind that message can be represented as an <strong>intent</strong>.</p>
<p>This creates an important testing question: Can the system understand the same intent when users express it differently?</p>
<p>A simple test set could look like this:</p>
<table>
<thead>
<tr>
<th>Utterance</th>
<th>Expected Intent</th>
</tr>
</thead>
<tbody><tr>
<td>I forgot my password</td>
<td>PASSWORD_RESET</td>
</tr>
<tr>
<td>How do I change my password?</td>
<td>PASSWORD_RESET</td>
</tr>
<tr>
<td>Can't get into my account</td>
<td>PASSWORD_RESET</td>
</tr>
<tr>
<td>Help me recover my login</td>
<td>PASSWORD_RESET</td>
</tr>
<tr>
<td>Password isn't working</td>
<td>PASSWORD_RESET</td>
</tr>
</tbody></table>
<p>Let's look at a small example:</p>
<pre><code class="language-python">test_cases = [ 
          { "message": "I forgot my password", 
            "expected_intent": "PASSWORD_RESET", 
          }, 
          { "message": "How do I change my password?", 
            "expected_intent": "PASSWORD_RESET", 
          }, 
          { "message": "Can't get into my account",  
            "expected_intent": "PASSWORD_RESET", 
          }, 
]

for test in test_cases: 
    response = ai_agent.send(test["message"])
    assert response.intent == test["expected_intent"]
</code></pre>
<p>Before running this test, you need to know the expected intent. It usually comes from the application's approved intent definitions or a reviewed test dataset. The automation isn't deciding what the correct intent should be. It's checking whether the AI agent classified the user's message according to the behavior the team already defined:</p>
<p><code>Input: "Can't get into my account"</code></p>
<p><code>Expected intent: PASSWORD_RESET Actual intent: PASSWORD_RESET</code></p>
<p><code>PASS</code></p>
<p>Don't stop with clean sentences.</p>
<p>Real users make spelling mistakes, use abbreviations, provide incomplete information, and sometimes type only a few words.</p>
<p>So I would also test:</p>
<p>"forgot pwd"</p>
<p>"cant login"</p>
<p>"password help"</p>
<p>"locked out"</p>
<p>This is where conversational AI testing starts becoming interesting. We're not testing whether the system recognizes one predefined sentence. We're testing whether it understands variations of a user's goal.</p>
<h2 id="heading-2-dont-use-exact-text-matching-for-every-response">2. Don't Use Exact Text Matching for Every Response</h2>
<p>One of the first habits I had to reconsider was comparing actual and expected responses word for word.</p>
<p>Suppose the expected answer is: "You can reset your password using the Forgot Password link."</p>
<p>But the AI responds: "Select Forgot Password on the login screen to begin resetting your password."</p>
<p>An exact string comparison fails. But from a user's perspective, the response may be completely correct.</p>
<p>Instead of defining the expected result as one sentence, define the <strong>properties a good response must contain</strong>.</p>
<p>For example, the response should:</p>
<ul>
<li><p>explain how to start the password-reset process</p>
</li>
<li><p>provide an actionable next step</p>
</li>
<li><p>not ask the user to reveal their password</p>
</li>
<li><p>avoid inventing account information</p>
</li>
<li><p>stay relevant to password recovery</p>
</li>
</ul>
<p>Now multiple responses can pass without being identical. This was one of the biggest changes for me.</p>
<p>For deterministic applications, expected output is often a value. For conversational AI, the expected result may need to be a <strong>set of evaluation criteria</strong>.</p>
<h2 id="heading-3-evaluate-response-quality-across-multiple-dimensions">3. Evaluate Response Quality Across Multiple Dimensions</h2>
<p>Correctness is important, but it shouldn't be the only thing you evaluate. I find it useful to break response quality into several dimensions.</p>
<ol>
<li><p>Accuracy: is the information correct? If the AI says customers can reset passwords through email when the actual process requires contacting support, the response fails even if it sounds convincing.</p>
</li>
<li><p>Relevance: did the AI answer what the user actually asked? A response can contain accurate information and still be irrelevant.</p>
</li>
<li><p>Completeness: did the response include the information required for the user to move forward?</p>
</li>
<li><p>Clarity: can the user easily understand the answer?</p>
</li>
<li><p>Helpfulness: does the response actually help the user accomplish their goal?</p>
</li>
</ol>
<p>A simple scoring rubric could look like this:</p>
<table>
<thead>
<tr>
<th>Criterion</th>
<th>Score</th>
</tr>
</thead>
<tbody><tr>
<td>Accuracy</td>
<td>0–2</td>
</tr>
<tr>
<td>Relevance</td>
<td>0–2</td>
</tr>
<tr>
<td>Completeness</td>
<td>0–2</td>
</tr>
<tr>
<td>Clarity</td>
<td>0–2</td>
</tr>
<tr>
<td>Helpfulness</td>
<td>0–2</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td><strong>0–10</strong></td>
</tr>
</tbody></table>
<p>You can then define a threshold appropriate for your application.</p>
<p>The exact scoring system isn't the important part. What's important is making the evaluation criteria explicit instead of relying on: "This answer looks good to me."</p>
<h2 id="heading-4-test-the-conversation-not-just-the-response">4. Test the Conversation, Not Just the Response</h2>
<p>Single-turn testing is useful, but users rarely interact with an AI agent using perfectly isolated questions.</p>
<p>Consider this conversation:</p>
<p><strong>User:</strong> I need to update my address.</p>
<p>The AI explains the process.</p>
<p>Then:</p>
<p><strong>User:</strong> Can I do that online?</p>
<p>What does <strong>"that"</strong> mean? The second message depends entirely on the first.</p>
<p>Now imagine:</p>
<p><strong>User:</strong> I need to update my address.</p>
<p><strong>AI:</strong> Sure. I can help with that.</p>
<p><strong>User:</strong> Actually, before that, can you tell me when my next payment is due?</p>
<p><strong>AI:</strong> Your next payment is due on September 15.</p>
<p><strong>User:</strong> Thanks. Now back to the address.</p>
<p>Can the system return to the original topic?</p>
<p>That's a different type of test.</p>
<p>Your multi-turn test suite should include scenarios such as:</p>
<ul>
<li><p>follow-up questions</p>
</li>
<li><p>references to earlier messages</p>
</li>
<li><p>topic switching</p>
</li>
<li><p>returning to a previous topic</p>
</li>
<li><p>user corrections</p>
</li>
<li><p>incomplete information</p>
</li>
<li><p>ambiguous questions</p>
</li>
<li><p>repeated questions</p>
</li>
</ul>
<p>This changed the unit of testing for me. Sometimes you're testing a response, while other times you're testing the entire conversation.</p>
<p>Here's an example:</p>
<pre><code class="language-python">ai_agent.send("My order number is A10245")
response = ai_agent.send("When will it arrive?")

assert response.order_id == "A10245"
</code></pre>
<p>The second message doesn't contain the order number. This check verifies that the AI agent retained information from the earlier turn instead of treating “When will it arrive?” as an unrelated question.</p>
<h2 id="heading-5-test-whether-the-ai-can-handle-corrections">5. Test Whether the AI Can Handle Corrections</h2>
<p>People change their minds and make mistakes.</p>
<p>For example:</p>
<p><strong>User:</strong> My account number ends in 4567.</p>
<p>Then:</p>
<p><strong>User:</strong> Sorry, I meant 4576.</p>
<p>What happens next?</p>
<p>The system should ideally use the corrected information rather than continuing with the original value.</p>
<p>The same principle applies to other conversational details.</p>
<p>"I'm traveling to Boston."</p>
<p>followed by:</p>
<p>"Actually, make that Chicago."</p>
<p>Or:</p>
<p>"I need the report for June."</p>
<p>followed by:</p>
<p>"Sorry, July."</p>
<p>These are useful tests because they expose whether the agent is genuinely maintaining conversational context or simply accumulating information without understanding which information is current.</p>
<h2 id="heading-6-test-ambiguity">6. Test Ambiguity</h2>
<p>Users don't always provide enough information.</p>
<p>Imagine someone types: "I want to change it."</p>
<p>Change what? Their address? Password? Payment method? Notification preference?</p>
<p>A poor conversational system may guess. A better one may ask: "What would you like to change?"</p>
<p>This gives us another important test category: <strong>clarification behavior.</strong></p>
<p>Create intentionally ambiguous utterances such as:</p>
<ul>
<li><p>"How do I update it?"</p>
</li>
<li><p>"It's not working."</p>
</li>
<li><p>"Can you change that?"</p>
</li>
<li><p>"I need help with my account."</p>
</li>
</ul>
<p>Then evaluate whether the AI recognizes that information is missing, avoids making unsupported assumptions, and asks an appropriate clarification question.</p>
<p>Sometimes the best AI response isn't an answer, it's another question.</p>
<h2 id="heading-7-test-the-knowledge-behind-the-answer">7. Test the Knowledge Behind the Answer</h2>
<p>At first, I focused almost entirely on what the AI said. Then I realized that a poor answer doesn't automatically mean the language model itself is the problem.</p>
<p>The system may be using a knowledge base, retrieval system, documentation, APIs, or other enterprise data sources.</p>
<p>If that information is wrong, incomplete, conflicting, or outdated, the AI may produce a poor response even when the model is behaving as designed.</p>
<p>Suppose the official policy says: Customers have 30 days to return a product. But an outdated knowledge article says that customers have 60 days.</p>
<p>If the AI retrieves the outdated article and confidently answers "60 days," the response is wrong.</p>
<p>But the investigation shouldn't end with: <strong>"The AI hallucinated."</strong> The tester needs to determine where the wrong information came from.</p>
<p>Questions I would investigate include:</p>
<ul>
<li><p>What source did the response use?</p>
</li>
<li><p>Was the source approved?</p>
</li>
<li><p>Is the information current?</p>
</li>
<li><p>Were multiple sources contradictory?</p>
</li>
<li><p>Did retrieval return the correct document?</p>
</li>
<li><p>Did the final response accurately represent the retrieved information?</p>
</li>
</ul>
<p>This becomes particularly important in systems using retrieval-augmented generation, or RAG.</p>
<h2 id="heading-8-test-for-hallucinations">8. Test for Hallucinations</h2>
<p>One of the most important conversational AI tests is surprisingly simple: <strong>Ask about something the system doesn't know.</strong></p>
<p>Suppose an internal support assistant contains documentation for Products A, B, and C. Ask: "What is the cancellation policy for Product Z?"</p>
<p>Product Z doesn't exist.</p>
<p>So what should happen? The worst outcome is for the system to confidently invent a cancellation policy.</p>
<p>Depending on the application, better behavior might be:</p>
<p>"I don't have information about Product Z."</p>
<p>or:</p>
<p>"I couldn't find that information. Would you like me to connect you with support?"</p>
<p>A useful hallucination test suite should include:</p>
<ul>
<li><p>nonexistent products</p>
</li>
<li><p>fake policy names</p>
</li>
<li><p>unsupported features</p>
</li>
<li><p>deliberately incorrect assumptions</p>
</li>
<li><p>questions outside the knowledge domain</p>
</li>
<li><p>requests for information unavailable to the system</p>
</li>
</ul>
<p>You're testing whether the AI knows when <strong>not</strong> to answer.</p>
<h2 id="heading-9-test-fallback-behavior">9. Test Fallback Behavior</h2>
<p>Every conversational system will eventually receive something it doesn't understand. But that isn't necessarily a failure.</p>
<p>The important question is what happens next?</p>
<p>Imagine a scenario like this:</p>
<p><strong>User:</strong> I need help with my ZXP adjustment.</p>
<p>The system doesn't recognize "ZXP."</p>
<p>A poor fallback might repeatedly say: "Sorry, I don't understand." A better fallback might ask: "Could you tell me a little more about what you mean by ZXP adjustment?"</p>
<p>If the system still can't understand the request, it may need to offer another path.</p>
<p>Fallback tests should cover:</p>
<ul>
<li><p>unknown intents</p>
</li>
<li><p>misspellings</p>
</li>
<li><p>incomplete requests</p>
</li>
<li><p>unsupported topics</p>
</li>
<li><p>conflicting requests</p>
</li>
<li><p>repeated misunderstanding</p>
</li>
</ul>
<p>Also test what happens after multiple failures. An AI agent shouldn't trap the user in an endless loop of: "Sorry, I didn't understand that."</p>
<h2 id="heading-10-test-human-escalation">10. Test Human Escalation</h2>
<p>Sometimes the AI agent should recognize that it can no longer handle the conversation reliably. This might happen when the user explicitly asks for a person, the request falls outside the agent's capabilities, or the situation requires human judgment. In those cases, continuing to generate answers may be worse than handing the conversation over</p>
<p>Consider situations involving:</p>
<ul>
<li><p>repeated misunderstanding</p>
</li>
<li><p>unsupported account problems</p>
</li>
<li><p>user requests for a human</p>
</li>
<li><p>sensitive workflows</p>
</li>
<li><p>exceptions the automated process cannot handle</p>
</li>
</ul>
<p>If escalation is part of the product design, test the entire transition.</p>
<p>For example:</p>
<p><strong>User:</strong> I want to speak to someone.</p>
<p>Does the AI recognize the request? Does it transfer the conversation correctly? Does the human agent receive the relevant conversation history? Does the user have to explain everything again? Does the AI continue trying to answer after escalation should have occurred?</p>
<p>A technically successful transfer can still create a poor experience if all the context is lost.</p>
<h2 id="heading-11-test-integrations-like-you-would-in-any-other-application">11. Test Integrations Like You Would in Any Other Application</h2>
<p>Conversational interfaces can make complex systems look simple.</p>
<p>The user sees:</p>
<p>"What's the status of my order?"</p>
<p>But behind that sentence, the agent might:</p>
<ol>
<li><p>identify the user's intent</p>
</li>
<li><p>authenticate the customer</p>
</li>
<li><p>call an order API</p>
</li>
<li><p>retrieve the order</p>
</li>
<li><p>interpret the response</p>
</li>
<li><p>generate a natural-language answer</p>
</li>
</ol>
<p>Traditional testing skills become extremely valuable here.</p>
<p>If the API returns:</p>
<pre><code class="language-json">{
  "order_id": "A10245",
  "status": "SHIPPED"
}
</code></pre>
<p>the AI shouldn't tell the user: "Your order is still processing."</p>
<p>To check these integrations, make sure you test:</p>
<ul>
<li><p>correct API mapping</p>
</li>
<li><p>authentication failures</p>
</li>
<li><p>timeouts</p>
</li>
<li><p>empty responses</p>
</li>
<li><p>malformed responses</p>
</li>
<li><p>unavailable services</p>
</li>
<li><p>incorrect status codes</p>
</li>
<li><p>partial data</p>
</li>
</ul>
<p>AI doesn't eliminate conventional integration testing. It adds another layer on top of it.</p>
<h2 id="heading-12-build-a-golden-dataset">12. Build a Golden Dataset</h2>
<p>Manual exploratory testing is useful when you're learning how an AI behaves, but eventually you need repeatability. This is where a <strong>golden dataset</strong> becomes useful.</p>
<p>A golden dataset is a curated collection of representative test inputs and expected behaviors that can be rerun as the system changes.</p>
<p>For example:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>User Input</th>
<th>Expected Behavior</th>
</tr>
</thead>
<tbody><tr>
<td>INT-001</td>
<td>Forgot password</td>
<td>Identify password-reset intent</td>
</tr>
<tr>
<td>INT-002</td>
<td>Can't access account</td>
<td>Route to account-access flow</td>
</tr>
<tr>
<td>CTX-001</td>
<td>Can I do that online?</td>
<td>Resolve previous conversational context</td>
</tr>
<tr>
<td>AMB-001</td>
<td>I want to change it</td>
<td>Ask clarification</td>
</tr>
<tr>
<td>HAL-001</td>
<td>Policy for nonexistent Product Z</td>
<td>Don't invent policy</td>
</tr>
<tr>
<td>ESC-001</td>
<td>Let me talk to a person</td>
<td>Initiate escalation</td>
</tr>
<tr>
<td>KB-001</td>
<td>What is the return period?</td>
<td>Answer according to approved knowledge</td>
</tr>
</tbody></table>
<p>Then expand each important intent with paraphrases, edge cases, negative cases, and multi-turn scenarios.</p>
<p>Whenever prompts, knowledge, models, integrations, or conversation logic change, rerun the dataset.</p>
<p>Now you have something much closer to traditional regression testing.</p>
<h2 id="heading-13-dont-only-measure-pass-rate">13. Don't Only Measure Pass Rate</h2>
<p>Suppose you execute 1,000 conversational tests and 950 pass. A 95% pass rate sounds good.</p>
<p>But what failed? Five hundred harmless FAQ questions? Or five critical account-security scenarios?</p>
<p>Aggregate pass rate alone doesn't tell the whole story. Depending on the application, useful metrics might include:</p>
<ul>
<li><p><strong>Intent recognition accuracy:</strong> How often was the user's goal understood correctly?</p>
</li>
<li><p><strong>Fallback rate:</strong> How often did the system fail to understand the user?</p>
</li>
<li><p><strong>Task completion rate:</strong> How often did users successfully accomplish the intended task?</p>
</li>
<li><p><strong>Escalation success rate:</strong> When human help was required, did the transition succeed?</p>
</li>
<li><p><strong>Grounding failures:</strong> How often did responses conflict with approved knowledge?</p>
</li>
<li><p><strong>Context failures:</strong> How often did the system lose important information during multi-turn conversations?</p>
</li>
<li><p><strong>Critical hallucinations:</strong> How often did the system confidently provide unsupported information?</p>
</li>
</ul>
<p>The right metrics depend on the product and its risks. A customer-service FAQ bot and an AI system supporting financial decisions shouldn't necessarily have the same quality thresholds.</p>
<h2 id="heading-14-create-risk-based-conversational-tests">14. Create Risk-Based Conversational Tests</h2>
<p>This is another traditional QA principle that transfers very well.</p>
<p>Not every AI failure has the same impact. If an AI responds awkwardly to: "What are your business hours?", that's inconvenient.</p>
<p>If it gives incorrect information about a payment, account security, healthcare instruction, or financial policy, the impact could be much greater.</p>
<p>So categorize scenarios by risk.</p>
<p>For example:</p>
<table>
<thead>
<tr>
<th>Risk</th>
<th>Example</th>
<th>Testing Priority</th>
</tr>
</thead>
<tbody><tr>
<td>Low</td>
<td>General FAQ</td>
<td>Normal</td>
</tr>
<tr>
<td>Medium</td>
<td>Account navigation</td>
<td>High</td>
</tr>
<tr>
<td>High</td>
<td>Financial/account action</td>
<td>Very High</td>
</tr>
<tr>
<td>Critical</td>
<td>Security/privacy behavior</td>
<td>Mandatory regression</td>
</tr>
</tbody></table>
<p>Then concentrate regression coverage on the scenarios where incorrect AI behavior would cause the greatest harm.</p>
<h2 id="heading-15-a-practical-conversational-ai-test-strategy">15. A Practical Conversational AI Test Strategy</h2>
<p>If I were starting a conversational AI QA effort today, I would organize it into these layers:</p>
<h3 id="heading-layer-1-intent-testing">Layer 1: Intent Testing</h3>
<p>Can the system understand what the user wants despite variations in language?</p>
<h3 id="heading-layer-2-response-evaluation">Layer 2: Response Evaluation</h3>
<p>Are responses accurate, relevant, complete, clear, and useful?</p>
<h3 id="heading-layer-3-conversation-testing">Layer 3: Conversation Testing</h3>
<p>Can the system maintain context across multiple turns?</p>
<h3 id="heading-layer-4-knowledge-and-grounding">Layer 4: Knowledge and Grounding</h3>
<p>Are answers supported by approved and current information?</p>
<h3 id="heading-layer-5-negative-and-hallucination-testing">Layer 5: Negative and Hallucination Testing</h3>
<p>Does the system avoid confidently answering when it doesn't have enough information?</p>
<h3 id="heading-layer-6-fallback-and-escalation">Layer 6: Fallback and Escalation</h3>
<p>Can the system recover when it doesn't understand, and can it hand off to a human when necessary?</p>
<h3 id="heading-layer-7-integration-testing">Layer 7: Integration Testing</h3>
<p>Are APIs, authentication, databases, and downstream systems behaving correctly?</p>
<h3 id="heading-layer-8-regression-testing">Layer 8: Regression Testing</h3>
<p>Can important behaviors be rerun after model, prompt, knowledge, or application changes?</p>
<p>That gives QA teams a much more structured starting point than simply opening a chatbot and asking random questions.</p>
<h2 id="heading-what-traditional-qa-engineers-already-bring-to-ai-testing">What Traditional QA Engineers Already Bring to AI Testing</h2>
<p>When I first started learning conversational AI, I thought I needed to forget everything I knew about traditional testing. But I don't believe that anymore.</p>
<p>A lot of our existing skills transfer extremely well. We already know how to:</p>
<ul>
<li><p>question assumptions</p>
</li>
<li><p>explore edge cases</p>
</li>
<li><p>design negative tests</p>
</li>
<li><p>trace failures through multiple systems</p>
</li>
<li><p>validate integrations</p>
</li>
<li><p>prioritize by risk</p>
</li>
<li><p>build regression suites</p>
</li>
<li><p>investigate unexpected behavior</p>
</li>
</ul>
<p>What changes is the definition of the expected result.</p>
<p>For some AI scenarios, the expected result isn't:</p>
<p><strong>Response = X</strong></p>
<p>It's closer to:</p>
<p><strong>The response must satisfy X, Y, and Z while avoiding A and B.</strong></p>
<p>Once I understood that distinction, conversational AI testing started making much more sense to me.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>My first instinct when learning conversational AI was to search for the test cases.</p>
<p>Now I think that's the wrong place to start. Start with the user.</p>
<ul>
<li><p>What are they trying to accomplish?</p>
</li>
<li><p>What are the different ways they might ask for it?</p>
</li>
<li><p>What information does the AI need?</p>
</li>
<li><p>What would a useful answer contain?</p>
</li>
<li><p>What should the system never say?</p>
</li>
<li><p>What happens if the AI doesn't know?</p>
</li>
<li><p>What happens when the conversation changes direction?</p>
</li>
<li><p>What evidence would make you confident enough to release that experience to real users?</p>
</li>
</ul>
<p>Those questions eventually become your test cases.</p>
<p>Conversational AI may be less deterministic than the applications many QA engineers are used to testing. But that doesn't make it untestable. It simply means we need to move beyond asking:</p>
<p>"Did I get the exact output I expected?"</p>
<p>and start asking:</p>
<p>"Did the system behave correctly, safely, and usefully across the different ways a real person might interact with it?"</p>
<p>For me, that was the biggest shift. The tools are changing, and so is the interface. Even the definition of an expected result is changing. But the fundamental responsibility of quality engineering hasn't changed very much at all: understand how the system can fail before the user has to discover it for you.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What Modern QA Engineers Actually Do: It's More Than Finding Bugs ]]>
                </title>
                <description>
                    <![CDATA[ Ask someone what a QA engineer does, and you'll probably hear a familiar answer: "They test software and find bugs." It's a common perception, and to be fair, finding bugs is an important part of the  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-does-a-modern-qa-engineer-do/</link>
                <guid isPermaLink="false">6a722e60649a71090a9c2307</guid>
                
                    <category>
                        <![CDATA[ Quality Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ automation testing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ career advice ]]>
                    </category>
                
                    <category>
                        <![CDATA[ QAengineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ GAYATHRI BOLINENI ]]>
                </dc:creator>
                <pubDate>Tue, 04 Aug 2026 18:24:32 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/55c4125f-a946-42b9-a694-46ab4cb3f6d6.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Ask someone what a QA engineer does, and you'll probably hear a familiar answer: <em>"They test software and find bugs."</em></p>
<p>It's a common perception, and to be fair, finding bugs is an important part of the job. But if you spend even a few weeks working on a modern software team, you'll quickly realize that's only a small part of what QA engineers actually do.</p>
<p>Software development has changed dramatically over the last decade. Teams no longer wait months to release new features. Many organizations deploy updates every week, every day, or even several times a day. Applications have become more complex, with cloud services, APIs, microservices, mobile apps, and third-party integrations all working together behind the scenes.</p>
<p>As software has evolved, the role of QA has evolved with it.</p>
<p>Today's QA engineers are involved long before a feature reaches testing. They help review requirements, identify risks, clarify business expectations, verify APIs and databases, automate repetitive tests, investigate production issues, and work closely with developers throughout the entire development lifecycle.</p>
<p>In other words, QA isn't just about finding problems after software has been built. It's about helping prevent those problems from happening in the first place.</p>
<p>Whether you're thinking about becoming a QA engineer, transitioning from manual testing into automation, or simply curious about what quality engineering looks like today, understanding how the role has changed is an important first step.</p>
<p>In this article, we'll explore what QA engineers actually do, why the profession has evolved, and the skills that have become essential for building reliable software in today's fast-moving development environments.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-how-the-qa-role-has-changed">How the QA Role Has Changed</a></p>
</li>
<li><p><a href="#heading-good-testing-starts-before-the-first-test-case">Good Testing Starts Before the First Test Case</a></p>
</li>
<li><p><a href="#heading-real-world-example">Real-world Example</a></p>
</li>
<li><p><a href="#heading-modern-qa-is-about-more-than-automation">Modern QA Is About More Than Automation</a></p>
</li>
<li><p><a href="#heading-where-different-types-of-testing-fit">Where Different Types of Testing Fit</a></p>
</li>
<li><p><a href="#heading-skills-every-qa-engineer-should-develop">Skills Every QA Engineer Should Develop</a></p>
</li>
<li><p><a href="#heading-common-misconceptions-about-qa">Common Misconceptions About QA</a></p>
</li>
<li><p><a href="#heading-if-youre-considering-a-career-in-qa">If You're Considering a Career in QA</a></p>
</li>
<li><p><a href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-how-the-qa-role-has-changed">How the QA Role Has Changed</h2>
<p>Many software usually teams followed a simple workflow. Business analysts gathered requirements, developers built the application, and once development was complete, the software was handed over to QA for testing. If defects were found, the application went back to the development team before eventually being released.</p>
<p>In that model, QA was often viewed as the final checkpoint before production. Testing happened after most of the important technical decisions had already been made.</p>
<p>That approach worked reasonably well when software releases happened only a few times a year. Teams had enough time to finish development, perform weeks of manual testing, fix defects, and prepare for a scheduled release.</p>
<p>Todays software development looks very different.</p>
<p>Many organizations use Agile methodologies, Continuous Integration (CI), and Continuous Delivery (CD). Instead of delivering software every few months, teams continuously add features, fix bugs, and release improvements in short development cycles.</p>
<p>Because development moves much faster, quality can no longer be treated as the final phase of a project.</p>
<p>Instead, QA engineers work alongside developers, product owners, business analysts, UX designers, and DevOps engineers from the beginning of the development process. They participate in sprint planning, review user stories, discuss acceptance criteria, identify potential risks, and help ensure new features are designed with testing in mind before development even starts.</p>
<p>This shift has changed the role of QA from <strong>testing completed software</strong> to <strong>helping teams build quality into the software from the start</strong>.</p>
<p>For example, imagine a team is building an online banking application that allows customers to transfer money between accounts. A traditional testing approach might focus on verifying whether the transfer succeeds after the feature has been developed.</p>
<p>An experienced QA engineer starts much earlier by asking questions such as:</p>
<ul>
<li><p>What happens if the network connection is interrupted during the transfer?</p>
</li>
<li><p>What should happen if the customer has insufficient funds?</p>
</li>
<li><p>Can the same transfer request be submitted twice accidentally?</p>
</li>
<li><p>How should the application respond if the receiving bank is temporarily unavailable?</p>
</li>
</ul>
<p>Questions like these help uncover potential problems before developers spend time writing code. Addressing these scenarios early is often much less expensive than discovering them during testing—or worse, after the application has been released to customers.</p>
<p>This is one of the biggest reasons QA has evolved from a role focused primarily on testing into one that contributes throughout the entire software development lifecycle.</p>
<p>Quality is no longer something that's checked at the end of a project.</p>
<p>It's something the entire team builds together, one decision at a time.</p>
<p><strong>Traditional Development</strong></p>
<p>Requirements -&gt; Development -&gt; QA Testing -&gt; Production</p>
<p><strong>Modern Development</strong></p>
<p>Requirement -&gt; DEV+QA+Product Owner -&gt; Continuous Development -&gt; Continuous Testing -&gt; Production</p>
<h2 id="heading-good-testing-starts-before-the-first-test-case">Good Testing Starts Before the First Test Case</h2>
<p>One of the biggest surprises for people entering software testing is discovering that a significant part of a QA engineer's work happens before a single test case is written.</p>
<p>Many people picture testing as something that begins only after developers finish building a feature. In reality, experienced QA engineers become involved much earlier because that's often where they can have the greatest impact.</p>
<p>Consider a simple requirement:</p>
<blockquote>
<p><strong>A user must create a password containing at least eight characters.</strong></p>
</blockquote>
<p>At first glance, the requirement seems complete. A developer can implement it, and a tester can verify that passwords shorter than eight characters are rejected.</p>
<p>But software requirements are rarely that straightforward.</p>
<p>A QA engineer naturally starts looking beyond the obvious by asking questions such as:</p>
<ul>
<li><p>Should spaces or count as characters? Or Should leading or trailing spaces be removed automatically?</p>
</li>
<li><p>Is there a maximum password length?</p>
</li>
<li><p>Are special or Unicode characters required?</p>
</li>
<li><p>Will the same validation rules apply on both the web application and the mobile app?</p>
</li>
<li><p>What error message should users see if the password is invalid?</p>
</li>
</ul>
<p>None of these questions are about trying to catch developers making mistakes.</p>
<p>They're about making sure the entire team has the same understanding of how the feature should work before development moves forward.</p>
<p>This process is often called <strong>requirement clarification</strong>, and it's one of the most valuable contributions a QA engineer can make.</p>
<p>Without these discussions, developers may implement one interpretation of the requirement while testers validate another. Business stakeholders may expect something entirely different. Even when everyone is working hard, unclear requirements can lead to unnecessary defects, rework, and frustration.</p>
<p>Asking thoughtful questions early helps avoid those situations.</p>
<p>It also saves time.</p>
<p>Finding an unclear requirement during a planning meeting usually takes a few minutes to resolve. Discovering the same issue after development, testing, and deployment can take hours—or even days—to investigate and fix.</p>
<p>Good QA isn't only about verifying that software works correctly.</p>
<p>It's also about helping ensure the team is building the right software in the first place.</p>
<h2 id="heading-real-world-example">Real-world Example</h2>
<p>Imagine an online shopping website that offers discount coupons.</p>
<p>The requirement says:</p>
<blockquote>
<p><strong>"Users can apply one coupon during checkout."</strong></p>
</blockquote>
<p>At first, it sounds simple.</p>
<p>A QA engineer might ask:</p>
<ul>
<li><p>What happens if the coupon has expired?</p>
</li>
<li><p>Can two browser tabs apply the same coupon simultaneously?</p>
</li>
<li><p>What if the customer removes an item after applying the coupon?</p>
</li>
<li><p>Can multiple coupons be combined?</p>
</li>
<li><p>What happens if the payment fails after the coupon has been applied?</p>
</li>
</ul>
<p>These questions often uncover situations that weren't considered during the initial discussion.</p>
<p>Instead of becoming production defects, they become design decisions that the team can address before writing code.</p>
<p>That's one of the reasons experienced QA engineers spend so much time asking questions. They're not slowing development down. They're helping the team avoid expensive surprises later.</p>
<h2 id="heading-modern-qa-is-about-more-than-automation">Modern QA Is About More Than Automation</h2>
<p>If you browse job postings for QA engineers, you'll probably notice one thing almost immediately.</p>
<p>Many of them mention automation tools such as Selenium, Plawright, Cypress, Appium, Javascript, Java, Python, and so on - the list goes on</p>
<p>Because of that, it's easy to assume that QA engineers spend their entire day writing automated tests. Automation is certainly an important part of the job, but it isn't the job itself.</p>
<p>Think about a new feature being added to a food delivery app. Customers can now save multiple delivery addresses and choose one during checkout. Before any automation script is written, a QA engineer is already involved.</p>
<p>They review the requirement to understand how the feature is expected to work. They discuss different scenarios with developers and product owners, such as what should happen if a customer deletes their default address or enters an invalid ZIP code. They identify edge cases that may not have been considered during planning and think about how the feature interacts with existing functionality.</p>
<p>Only after those discussions do they begin designing test scenarios.</p>
<p>Some of those tests may eventually become automated, especially if the feature will be used in future regression testing. Others may be better suited for exploratory testing because they require human observation and judgment.</p>
<p>QA engineers choose the right testing approach based on the problem they're trying to solve rather than trying to automate everything.</p>
<p>A typical week for a QA engineer might include a variety of responsibilities, such as:</p>
<ul>
<li><p>Reviewing new requirements before development begins.</p>
</li>
<li><p>Designing functional and edge-case test scenarios.</p>
</li>
<li><p>Verifying REST API responses using tools like Postman or Bruno.</p>
</li>
<li><p>Validating backend data with SQL queries.</p>
</li>
<li><p>Building or maintaining automated regression tests.</p>
</li>
<li><p>Investigating issues reported from production.</p>
</li>
<li><p>Working with developers to reproduce and understand defects.</p>
</li>
<li><p>Confirming bug fixes before a release.</p>
</li>
</ul>
<p>Some weeks involve more automation than others. Some involve more investigation, collaboration, or exploratory testing.</p>
<p>That's one of the reasons QA engineering is such a diverse field. No two projects are exactly the same, and the work changes depending on the product, the team, and the stage of development.</p>
<p>Automation simply helps QA engineers spend less time repeating predictable tasks so they can focus on the work that requires critical thinking.</p>
<p>It's a tool that supports quality engineering—not the definition of it.</p>
<h2 id="heading-where-different-types-of-testing-fit">Where Different Types of Testing Fit</h2>
<p>Another common misconception is that QA engineers only test the user interface. In reality, software can be tested at many different levels.</p>
<p>For example:</p>
<table>
<thead>
<tr>
<th>Type of Testing</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><strong>UI Testing</strong></td>
<td>Verifies that users can successfully interact with the application.</td>
</tr>
<tr>
<td><strong>API Testing</strong></td>
<td>Confirms that services communicate correctly and return the expected responses.</td>
</tr>
<tr>
<td><strong>Database Testing</strong></td>
<td>Validates that data is stored, updated, and retrieved accurately.</td>
</tr>
<tr>
<td><strong>Regression Testing</strong></td>
<td>Ensures that new changes haven't broken existing functionality.</td>
</tr>
<tr>
<td><strong>Exploratory Testing</strong></td>
<td>Helps uncover unexpected issues through human observation and creativity.</td>
</tr>
<tr>
<td><strong>Performance Testing</strong></td>
<td>Evaluates how the application behaves under different workloads.</td>
</tr>
</tbody></table>
<p>QA engineers don't necessarily perform all of these types of testing every day, but understanding when and why each approach is useful helps them choose the right strategy for different situations.</p>
<p>Quality isn't achieved by relying on a single testing technique.</p>
<p>It's achieved by combining multiple testing approaches to build confidence that the software behaves correctly under real-world conditions.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a680c143c3aac7c9e746cad/deb53c30-0cef-4708-ae8e-43ca86e03b0d.png" alt="A flowchart showing how a new software feature is validated through UI testing, API testing, and database testing before entering regression testing and finally being released to production" style="display: block;" width="1433" height="992" loading="lazy">

<h2 id="heading-skills-every-qa-engineer-should-develop">Skills Every QA Engineer Should Develop</h2>
<p>If you're just starting your QA journey, it's easy to focus on learning specific tools. While tools are important, they're only part of the picture. The most successful QA engineers build a combination of technical skills, problem-solving abilities, and effective communication.</p>
<p>Here are some of the core skills that will help you grow in QA role.</p>
<table>
<thead>
<tr>
<th><strong>Skill</strong></th>
<th><strong>Why It Matters</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>Communication</strong></td>
<td>Helps clarify requirements, explain defects, and collaborate effectively with the team.</td>
</tr>
<tr>
<td><strong>Critical Thinking</strong></td>
<td>Identifies edge cases, risks, and scenarios that may not be immediately obvious.</td>
</tr>
<tr>
<td><strong>API Testing</strong></td>
<td>Verifies how applications communicate and ensures backend services behave correctly.</td>
</tr>
<tr>
<td><strong>SQL</strong></td>
<td>Confirms that data is stored, updated, and retrieved accurately from databases.</td>
</tr>
<tr>
<td><strong>Test Automation</strong></td>
<td>Reduces repetitive testing and improves regression testing efficiency.</td>
</tr>
<tr>
<td><strong>CI/CD Knowledge</strong></td>
<td>Helps integrate testing into modern software delivery pipelines.</td>
</tr>
<tr>
<td><strong>Continuous Learning</strong></td>
<td>Keeps your skills current as tools, technologies, and development practices evolve.</td>
</tr>
</tbody></table>
<p>We don't need to masters all of these skills overnight. The important thing is to build a strong foundation, stay curious, and keep learning as the industry evolves.</p>
<h2 id="heading-common-misconceptions-about-qa">Common Misconceptions About QA</h2>
<p>If you're new to software testing, you've probably heard some of these statements before. While they may sound reasonable, they don't reflect how modern QA teams actually work.</p>
<h3 id="heading-myth-qa-engineers-only-find-bugs">Myth: QA engineers Only Find Bugs</h3>
<p><strong>Reality:</strong> Finding bugs is only one part of the job. QA engineers also review requirements, identify risks, design test strategies, automate repetitive testing, validate APIs and databases, and help teams prevent defects before software reaches users.</p>
<h3 id="heading-myth-automation-will-replace-qa-engineers">Myth: Automation Will Replace QA Engineers.</h3>
<p><strong>Reality:</strong> Automation is a tool, not a replacement for human thinking. Automated tests can execute repetitive tasks, but they can't decide what should be tested, identify unclear requirements, or evaluate whether a feature delivers a good user experience.</p>
<h3 id="heading-myth-qa-is-responsible-for-quality">Myth: QA is Responsible for Quality.</h3>
<p><strong>Reality:</strong> Quality is a shared responsibility. Developers write reliable code, product owners define clear requirements, designers focus on usability, DevOps engineers build dependable deployment pipelines, and QA engineers help ensure everything works together as expected.</p>
<h3 id="heading-myth-manual-testing-is-no-longer-useful">Myth: Manual Testing is No Longer Useful.</h3>
<p><strong>Reality:</strong> Automation is excellent for repetitive regression testing, but manual testing remains valuable for exploratory testing, usability checks, and investigating unexpected behavior. The two approaches complement each other rather than compete.</p>
<h3 id="heading-myth-qa-is-easier-than-software-development">Myth: QA is Easier than Software Development.</h3>
<p><strong>Reality:</strong> Modern QA requires strong analytical thinking, technical knowledge, communication skills, and a solid understanding of how software systems work. While the responsibilities differ from software development, both roles play an equally important part in delivering high-quality software.</p>
<h2 id="heading-if-youre-considering-a-career-in-qa">If You're Considering a Career in QA</h2>
<p>If you're thinking about becoming a QA engineer, don't worry if you don't know every testing tool or automation framework yet. Every experienced QA professional started by learning the fundamentals.</p>
<p>Begin by understanding how software works. Learn how web applications communicate with APIs, how data is stored in databases, and how different components interact to deliver a feature. These concepts will help you understand <em>why</em> you're testing something, not just <em>how</em> to test it.</p>
<p>At the same time, practice thinking like a user. Ask questions, explore different scenarios, and look beyond the "happy path." Some of the most valuable defects are discovered simply because someone asked, <em>"What happens if this doesn't go as expected?"</em></p>
<p>As you grow, gradually build technical skills such as SQL, API testing, automation, version control, and CI/CD. Focus on continuous learning and improving one skill at a time.</p>
<p>Most importantly, remember that software quality isn't created by one person or one team. The best QA engineers work collaboratively, communicate effectively, and help everyone build better software together.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Software testing has come a long way from being viewed as the final step before a release.</p>
<p>Today's QA engineers contribute throughout the software development lifecycle. They ask thoughtful questions, clarify requirements, automate repetitive testing, validate APIs and databases, investigate production issues, and help teams deliver reliable software with confidence.</p>
<p>Finding bugs will always be an important part of the role, but it's no longer what defines a successful QA engineer.</p>
<p>What truly makes a difference is the ability to prevent problems before they happen, think critically about how software is used, and collaborate with the entire team to deliver a better product.</p>
<p>If you're just starting your journey in software quality, don't measure your progress by how many testing tools you've learned. Focus on building strong fundamentals, staying curious, and continuously improving your problem-solving skills.</p>
<p>Technology will continue to evolve, but those qualities will always be valuable.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Your First Dynamic Performance Test in Apache JMeter ]]>
                </title>
                <description>
                    <![CDATA[ As a QA engineer, I have always found performance testing to be one of the most exciting and underrated parts of software testing. Yes, functional testing is important, but it’s of little use if users have to wait for 5 seconds for each page to load.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-your-first-dynamic-performance-test-in-apache-jmeter/</link>
                <guid isPermaLink="false">6900f3ca65a053299e38eab3</guid>
                
                    <category>
                        <![CDATA[ Scale Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Performance Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ jmeter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ scalability ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mah Noor ]]>
                </dc:creator>
                <pubDate>Tue, 28 Oct 2025 16:48:10 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761335397152/cb105a44-4c18-4998-9ffb-d520df0e6510.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a QA engineer, I have always found performance testing to be one of the most exciting and underrated parts of software testing. Yes, functional testing is important, but it’s of little use if users have to wait for 5 seconds for each page to load.</p>
<p>For me personally, there is a deep satisfaction that comes with seeing your product come alive under load to find out how it’ll actually work in production when thousands of users will be using it.</p>
<p>Performance testing is about discovering how your system performs under real-world pressure in terms of load, concurrency, and throughput. One of the key aspects of performance testing is ensuring that the APIs can endure the expected load. You can do this using tools like Apache JMeter and K6.</p>
<p>In this tutorial, we’ll explore how you can build your first end-to-end performance test in Apache JMeter. You will be learning to create a test suite that is dynamic (the test can be run with any test data) and that’s one-click executable (the test execution can be done through the GUI as well as the CLI).</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-introduction-to-apache-jmeter">Introduction to Apache JMeter</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-create-a-new-test-plan">Step 1: Create a New Test Plan</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-configure-the-thread-group">Step 2: Configure the Thread Group</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-add-http-request-defaults">Step 3: Add HTTP Request Defaults</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-add-a-csv-data-set-config-dynamic-input">Step 4: Add a CSV Data Set Config (Dynamic Input)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-add-the-http-request-sampler">Step 5: Add the HTTP Request Sampler</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-add-a-json-extractor">Step 6: Add a JSON Extractor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-add-an-assertion">Step 7: Add an Assertion</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-8-add-listeners">Step 8: Add Listeners</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-9-run-your-test">Step 9: Run Your Test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-10-chain-another-request-optional">Step 10: Chain Another Request (Optional)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-11-analyze-the-results">Step 11: Analyze the Results</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-pro-tips">Pro Tips</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-folder-structure">Example Folder Structure:</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start, make sure you have:</p>
<ul>
<li><p><a target="_blank" href="https://jmeter.apache.org/download_jmeter.cgi"><strong>Apache JMeter (5.5 or above)</strong></a> installed.</p>
</li>
<li><p><a target="_blank" href="https://www.java.com/en/download/manual.jsp"><strong>Java 8 or later</strong></a> configured on your system.</p>
</li>
</ul>
<p>You can check if JMeter is installed by running the command below:</p>
<pre><code class="lang-plaintext">jmeter -v
</code></pre>
<p><strong>Note:</strong> This tutorial will use the <a target="_blank" href="https://jsonplaceholder.typicode.com/">JSONPlaceholder</a> public API. You’ll learn how you can get a post_id and use it in a chain request to get user details.</p>
<p>Let’s get started.</p>
<h2 id="heading-introduction-to-apache-jmeter">Introduction to Apache JMeter</h2>
<p>Apache JMeter is an open-source API load and stress testing tool. It’s a powerful testing tool that supports a wide range of protocols, including HTTP, HTTPS, FTP, JDBC, SOAP, and REST.</p>
<p>JMeter helps you answer critical questions about your APIs, like:</p>
<ul>
<li><p>How does my API perform under heavy load?</p>
</li>
<li><p>What’s the maximum number of users it can handle before it starts failing?</p>
</li>
<li><p>Which requests or endpoints are slowing things down?</p>
</li>
</ul>
<p>Let’s go through the step-by-step process of building a dynamic load testing suite with JMeter.</p>
<h3 id="heading-step-1-create-a-new-test-plan">Step 1: Create a New Test Plan</h3>
<p>Once JMeter opens, you’ll see an empty Test Plan. Think of this as your main workspace, which holds everything: Test configuration, users, requests, assertions, and results.</p>
<p>Right-click on <strong>Test Plan → Add → Threads (Users) → Thread Group</strong> to add a thread group. A thread group is essentially a test suite containing our test cases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761045558747/ad3a2fe3-de59-420f-ba9d-1a36323e1d9e.png" alt="Add Thread Group" width="1920" height="1009" loading="lazy"></p>
<h3 id="heading-step-2-configure-the-thread-group">Step 2: Configure the Thread Group</h3>
<p>To configure the thread group, fill out the following input fields:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Setting</td><td>Value</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>Number of Threads (Users)</td><td>5</td><td>This represents the number of concurrent users. In this case, it will be ‘5’</td></tr>
<tr>
<td>Ramp-up Period (seconds)</td><td>10</td><td>This means the time it takes the threads to reach the maximum value.</td></tr>
<tr>
<td>Loop Count</td><td>2</td><td>This specifies the number of times you want your thread group executed.</td></tr>
</tbody>
</table>
</div><p>You’ve now created a small, controlled load test of 10 total requests (5 users × 2 loops).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761049951497/8221336c-5f10-4161-81fa-d0ad27c7164f.png" alt="Thread Group" class="image--center mx-auto" width="1920" height="982" loading="lazy"></p>
<h3 id="heading-step-3-add-http-request-defaults">Step 3: Add HTTP Request Defaults</h3>
<p>When you’re creating a suite of 100s of APIs, you don’t need to add your request details to all the API samplers in JMeter. JMeter lets you set it once globally by using a config element called HTTP Request Defaults. To add this element, follow the steps below:</p>
<ol>
<li><p>Right-click on <strong>Thread Group → Add → Config Element → HTTP Request Defaults.</strong></p>
</li>
<li><p>Enter the following:</p>
<ul>
<li><p><strong>Protocol:</strong> <code>https</code></p>
</li>
<li><p><strong>Server Name or IP:</strong> <a target="_blank" href="http://jsonplaceholder.typicode.com"><code>jsonplaceholder.typicode.com</code></a></p>
</li>
</ul>
</li>
</ol>
<p>This means all requests in this test will automatically use this base URL.</p>
<h3 id="heading-step-4-add-a-csv-data-set-config-dynamic-input">Step 4: Add a CSV Data Set Config (Dynamic Input)</h3>
<p>In real projects, APIs rarely use static inputs. Take as an example a login API that you want to run for 100 concurrent users. In a real-world scenario, every login request will have a different username and password.</p>
<p>To replicate this on JMeter, you need to run your test for 100 different login credentials. This means that your test should be <strong>test data-driven</strong>. We can build a data-driven test in JMeter using a <strong>CSV file</strong>:</p>
<ol>
<li><p>Create a file named <code>data.csv</code> with the following content:</p>
<pre><code class="lang-plaintext"> post_id
 1
 2
 3
 4
 5
</code></pre>
</li>
<li><p>Save it in your JMeter project folder.</p>
</li>
<li><p>In JMeter, right-click on <strong>Thread Group → Add → Config Element → CSV Data Set Config.</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761048312824/4558aae4-23c8-446d-89d0-237aca29619d.png" alt="Add CSV Data Set Config" class="image--center mx-auto" width="1169" height="974" loading="lazy"></p>
</li>
<li><p>Fill in the following fields:</p>
<ul>
<li><p><strong>Filename:</strong> <code>data.csv</code></p>
</li>
<li><p><strong>Variable Names:</strong> <code>post_id</code></p>
</li>
<li><p><strong>Recycle on EOF:</strong> <code>True</code></p>
</li>
<li><p><strong>Stop thread on EOF:</strong> <code>False</code></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761048167041/eae27f5c-6e23-4c7d-8890-b3eb5943bb66.png" alt="CSV Data Set Config" class="image--center mx-auto" width="1437" height="642" loading="lazy"></p>
</li>
</ul>
</li>
</ol>
<p>Now each user will pick a new <code>post_id</code> for every iteration from the CSV file.</p>
<h3 id="heading-step-5-add-the-http-request-sampler">Step 5: Add the HTTP Request Sampler</h3>
<p>Now let’s add the actual API call we'll test under load. To do this, follow the steps below:</p>
<ol>
<li><p>Right-click on <strong>Thread Group → Add → Sampler → HTTP Request.</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761051865320/92bf89d0-616c-4d07-9531-3985265e07d7.png" alt="Add an HTTP Request" class="image--center mx-auto" width="1920" height="1017" loading="lazy"></p>
</li>
<li><p>Rename it to <strong>Get Post Data.</strong></p>
</li>
<li><p>Set the following fields:</p>
<ul>
<li><p><strong>Method:</strong> GET</p>
</li>
<li><p><strong>Path:</strong> <code>/posts/${post_id}</code></p>
</li>
</ul>
</li>
</ol>
<p>Here <code>${post_id}</code> dynamically takes its value from your CSV file. The Protocol and Server IP fields will automatically get data from the ‘HTTP Request default’ config element that we added in Step #3.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761049282841/a420139c-4622-4d7a-ac7d-4308bb9a1dbc.png" alt="Add a GET Request" class="image--center mx-auto" width="1920" height="904" loading="lazy"></p>
<h3 id="heading-step-6-add-a-json-extractor">Step 6: Add a JSON Extractor</h3>
<p>When the API returns a response, we can extract a value (like <code>userId</code>) from it and use it later. This is used to implement an end-to-end flow where data is gotten (with GET) from an API and sent to the next POST/DELETE API.</p>
<p>For our API, below is the example response:</p>
<pre><code class="lang-plaintext">{
  "userId": 1,
  "id": 3,
  "title": "fugiat veniam minus",
  "body": "This is an example post body"
}
</code></pre>
<p>To extract <code>userId</code>:</p>
<ol>
<li><p>Right-click on <strong>Get Post Data → Add → Post Processors → JSON Extractor.</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761051791176/b7888a78-efbb-48d3-8aba-fcd21edfd8f2.png" alt="Add JSON Extractor" class="image--center mx-auto" width="1920" height="1018" loading="lazy"></p>
</li>
<li><p>Set the variables below in the JSON Extractor:</p>
<ul>
<li><p><strong>Name:</strong> Extract User ID</p>
</li>
<li><p><strong>Variable Name:</strong> <code>user_id</code></p>
</li>
<li><p><strong>JSON Path Expression:</strong> <code>$.userId</code></p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761049324410/8a163733-8925-4557-9ace-124b08167f8e.png" alt="JSON Extractor" class="image--center mx-auto" width="1920" height="971" loading="lazy"></p>
<p>Now you can use <code>${user_id}</code> in the next request, making your test fully dynamic.</p>
<h3 id="heading-step-7-add-an-assertion">Step 7: Add an Assertion</h3>
<p>Assertions help you verify that your API responds correctly even under load. You can assert on the API response code, response time, or even the response payload. To add an assertion, follow the steps below:</p>
<ol>
<li><p>Right-click <strong>Get Post Data → Add → Assertions → Response Assertion.</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761049384591/a0293eef-74a0-4d55-b0c4-232d5c5eaa0c.png" alt="Add Response Assertion" class="image--center mx-auto" width="1920" height="1020" loading="lazy"></p>
</li>
<li><p>Configure as:</p>
<ul>
<li><p><strong>Response Field to Test:</strong> <em>Response Code –</em> This will add an assertion for the response code.</p>
</li>
<li><p><strong>Pattern Matching Rules:</strong> <em>Contains</em></p>
</li>
<li><p><strong>Pattern to Test:</strong> 200</p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761050184412/5a52f600-74f6-48c7-a975-7e39df47afdb.png" alt="Add Response Assertion" class="image--center mx-auto" width="1920" height="1017" loading="lazy"></p>
<p>This ensures JMeter only counts the request as successful if the word <code>fugiat</code> appears in the response.</p>
<h3 id="heading-step-8-add-listeners">Step 8: Add Listeners</h3>
<p>We’ll add listeners to display our test results in different forms, such as visually or in a summary. Let’s add two essential ones:</p>
<ol>
<li><p><strong>View Results Tree</strong>: to view and debug individual requests.</p>
</li>
<li><p><strong>Summary Report</strong>: to view performance metrics like response time, error rate, and throughput.</p>
</li>
</ol>
<p>Add them via <strong>Thread Group → Add → Listener → [Choose Listener]</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761049568483/0daa916c-503d-4f91-ad17-1d2bd29a9f72.png" alt="Add Listener in JMeter" class="image--center mx-auto" width="1920" height="1020" loading="lazy"></p>
<h3 id="heading-step-9-run-your-test">Step 9: Run Your Test</h3>
<p>Hit the green <strong>Start</strong> button at the top. JMeter will start sending requests to your API using the dynamic post IDs from your CSV file.</p>
<p>As the test runs:</p>
<ul>
<li><p>Green checkmarks in <strong>View Results Tree</strong> mean successful responses.</p>
</li>
<li><p>Assertion failures will appear in red.</p>
</li>
<li><p><strong>Summary Report</strong> will aggregate key metrics.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761050151356/d8c72408-cf91-4c9d-8663-0a65b6943f5b.png" alt="JMeter View Results Tree" class="image--center mx-auto" width="1920" height="1013" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761050211424/532dd999-b870-4cf8-ad1e-1a692119b0e0.png" alt="JMeter Summary Report" class="image--center mx-auto" width="1920" height="1024" loading="lazy"></p>
<h3 id="heading-step-10-chain-another-request-optional">Step 10: Chain Another Request (Optional)</h3>
<p>Let’s take it one step further: we’ll use the extracted <code>user_id</code> from the first response to get user details from the <a target="_blank" href="https://jsonplaceholder.typicode.com/users">GET users call</a>. To do this, follow the steps below:</p>
<ol>
<li><p>Right-click <strong>Thread Group → Add → Sampler → HTTP Request.</strong></p>
</li>
<li><p>Rename to <strong>Get User Details.</strong></p>
</li>
<li><p>Set:</p>
<ul>
<li><p><strong>Method:</strong> GET</p>
</li>
<li><p><strong>Path:</strong> <code>/users/${user_id}</code></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761050384264/dcc1c333-4e06-4dd9-8dca-9af823fedabd.png" alt="GET Users API" class="image--center mx-auto" width="1920" height="1015" loading="lazy"></p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761050365937/736b9954-6d01-45a6-8c16-f6d2ceb60e10.png" alt="Test Execution in JMeter" class="image--center mx-auto" width="1920" height="1021" loading="lazy"></p>
<h3 id="heading-step-11-analyze-the-results">Step 11: Analyze the Results</h3>
<p>Once the test completes, open the <strong>Summary Report</strong>. You’ll see:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Metric</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Sample Count</strong></td><td>Number of total requests sent</td></tr>
<tr>
<td><strong>Average</strong></td><td>Mean response time per request</td></tr>
<tr>
<td><strong>Min/Max</strong></td><td>Fastest and slowest response times</td></tr>
<tr>
<td><strong>Error %</strong></td><td>Percentage of failed requests</td></tr>
<tr>
<td><strong>Throughput</strong></td><td>Requests handled per second</td></tr>
</tbody>
</table>
</div><p>If your error percentage is 0% and throughput is stable, your system handled the load well.</p>
<h3 id="heading-pro-tips">Pro Tips</h3>
<ul>
<li><p><strong>Parameterize everything.</strong> Use multiple CSVs for realistic test flows (users, IDs, tokens).</p>
</li>
<li><p><strong>Add timers</strong> (like <em>Constant Timer</em>) to simulate think time between user actions.</p>
</li>
<li><p><strong>Use Assertions wisely.</strong> Don’t add extra assertions; focus on key validations such as response time and API status code.</p>
</li>
<li><p><strong>Generate HTML reports using the command below:</strong></p>
<pre><code class="lang-plaintext">  jmeter -n -t test-plan.jmx -l results.jtl -e -o report
</code></pre>
</li>
</ul>
<h3 id="heading-example-folder-structure">Example Folder Structure:</h3>
<p>Follow the folder structure below for an organized test suite.</p>
<pre><code class="lang-plaintext">performance-test/
├── data.csv
├── test-plan.jmx
└── results/
    ├── summary.csv
    └── report.html
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Performance testing is an essential element of a production readiness checklist for any product. It helps you ensure that your product can handle the expected user load and scale gracefully.</p>
<p>This guide is your first step towards writing end-to-end performance test cases and bridging the gap between being a functional test engineer and a full-stack QA Engineer who understands both quality and scalability.</p>
<p>I hope you found this tutorial helpful. If you want to stay connected or learn more about performance testing, follow me on <a target="_blank" href="https://www.linkedin.com/in/mah-noorqa/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write QA Documentation That Will Actually Work ]]>
                </title>
                <description>
                    <![CDATA[ Imagine developing a complex software product without taking any action to protect against errors. Human error and unexpected code combinations can cause a wide range of defects. This is where quality assurance (QA) documentation comes in.  Usually, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-qa-documentation-that-will-actually-work/</link>
                <guid isPermaLink="false">66be14ba0c9c630f4d48debb</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oleh Romanyuk ]]>
                </dc:creator>
                <pubDate>Mon, 17 Jun 2024 18:29:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/How-to-Write-QA-Documentation-That-Will-Actually-Work.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine developing a complex software product without taking any action to protect against errors. Human error and unexpected code combinations can cause a wide range of defects. This is where quality assurance (QA) documentation comes in. </p>
<p>Usually, a QA tester creates a report after discovering a bug. The next step is that they send a report to the bug handler. Basically, a bug handler is a developer that fixes a bug according to the detailed report. The bug handler ensures a clean and efficient QA process and makes it easier to have a clean conversation between the fixers and the testers. </p>
<p>But you might be wondering – why do we need QA documentation?</p>
<p>QA testing is essential in IT products today. Tight deadlines, unique skill sets within the organization, and the demand to develop products stress the need for a structured methodology. QA documentation guides testers through levels of clarity and overall coverage. </p>
<p>I've written this article to make your life a bit easier. So here it is, your ultimate guide on how to write software QA documentation that will work.</p>
<h3 id="heading-this-is-what-well-cover">This is what we'll cover:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-make-a-test-plan-and-a-test-progress-report">Make a Test Plan and a Test Progress Report</a></li>
<li><a class="post-section-overview" href="#heading-create-test-cases">Create Test Cases</a></li>
<li><a class="post-section-overview" href="#heading-defect-reports">Defect Reports</a></li>
<li><a class="post-section-overview" href="#heading-useful-tips-for-defect-report-writing">Useful Tips for Defect Report Writing</a></li>
<li><a class="post-section-overview" href="#heading-submit-a-defect-report">Submit a Defect Report</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-make-a-test-plan-and-a-test-progress-report">Make a Test Plan and a Test Progress Report</h2>
<p>Developing great software requires a thorough and documented approach to testing. Everything begins in the development phase with a complete checkout plan as a template for the entire QA process. It outlines the general requirements, defines the followed route, identifies the necessary assets, and sets a simple timeline for achieving the objectives.</p>
<h3 id="heading-draw-up-a-roadmap-before-you-start">Draw up a roadmap before you start</h3>
<p>Before you start implementing your test plan, take some time to think about the big picture. Ask yourself:</p>
<p><em>What problem does this software solve?</em> As soon as you understand the main purpose of the software, you'll be able to manage the checkout process and identify the features that are most important to your goals. </p>
<p>I promise that once you see that you can do this, you quickly prioritize your efforts. They are based primarily on the importance of the functionality and its impact on the user.</p>
<h3 id="heading-create-a-plan">Create a plan</h3>
<p>The test plan is the central part of the QA technique. The test plan should contain the following key elements:</p>
<ul>
<li><strong>Imaginary test</strong>: Clearly identify the expected impact of the payment method. Will it confirm that core functionality is running smoothly, or will it alert you to capability gaps?</li>
<li><strong>Test method</strong>: Outline how the test will be performed. Will you do targeted testing, useless testing, or a mix of the two?</li>
<li><strong>Resource allocation</strong>: Identify the equipment and technology required to perform a complete control. What control framework will you use? Are specific hardware or software configurations required for proper control?</li>
<li><strong>Timetable and remaining dates</strong>: Establish a realistic timetable for the trial. Set clear deadlines to keep the project on track.</li>
</ul>
<h3 id="heading-understand-the-why-and-how">Understand the 'why' and 'how'</h3>
<p>A well-developed roadmap will ensure that key issues are addressed throughout the improvement approach:</p>
<ul>
<li><strong>Acceptance requirements</strong>: Clear fail/success criteria should be defined for all control cases. So, criteria allow the customer to understand that the product is high quality and ready for the end-user.</li>
<li><strong>Resource management</strong>: Identify the assets required for the testing. This includes preferred machines, copies of software in various forms, required expertise, and more.</li>
<li><strong>Team dynamics</strong>: Ensure that simple roles and tasks are defined within the test team. Who is responsible for particular test cases? Who documents bugs and who talks to developers?</li>
<li><strong>Time management</strong>: I advise setting realistic checkout times, taking into account project deadlines and the availability of useful help.</li>
</ul>
<p>The test progress report is another part of the QA documentation, similar to the test plan, but with additional data on current progress. This document allows you and your development team to monitor project progress and identify any organizational issues.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/test-plan-and-progress-report-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>A test plan and a progress report</em></p>
<h2 id="heading-create-test-cases">Create Test Cases</h2>
<p>Think of each test case as a detailed recipe for finding potential defects in the functionality of a software program. By following these "recipes" and evaluating the expected and actual results, defects can be accurately identified and addressed before preventive action is taken. </p>
<p>Each test case acts as an independent unit, outlining the steps required to evaluate a particular element of a software program. </p>
<p>Below is a breakdown of the key elements that make up a well-defined test case Here is my step-by-step guide for creating test cases:</p>
<ul>
<li><strong>ID</strong>: This is an identifier field to help distinguish between test cases and track them easily.</li>
<li><strong>Priority</strong>: This indicates the severity of the test case based on the functionality of the program and its impact on the normal overall performance of the known software program application.</li>
<li><strong>Test Requirements</strong>: These are requirements for testing software successfully, this can include reference documents also.</li>
<li><strong>Software Module</strong>: This shows the feature under testing. It also refers to the software requirements specifications (SRS) document explaining the software feature in detail.</li>
<li><strong>Test Context</strong>: This details the test plan to clarify how the daily tests will be carried out. It also identifies the test data required for a successful case study and includes unique and important statistical information.</li>
<li><strong>Expected Output</strong>: This describes the expected output to be displayed if the test is successful.</li>
<li><strong>Actual output</strong>: This indicates the actual result in the event of failure and shows the developer the errors in the application module of the software program.</li>
<li><strong>Comment</strong>: This is an optional section where the tester can give a description of the observations or add additional records.</li>
</ul>
<p>All QAs typically include the above elements, but can also be designed specifically for the task selected by the QA group. Also, each control case follows a lifecycle that defines the phases of creation, testing (pass, fail), completion, and so on. </p>
<p>In the next section, we’ll check out another important element of QA documentation: the defect report.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/test-cases.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test cases</em></p>
<h2 id="heading-defect-reports">Defect Reports</h2>
<p>Defect reporting is an important element of QA documentation. Issue tracking is the detailed reporting of sudden problems that arise in a software product. Careful documentation of these issues lays the groundwork for a complex and bug-free final product. </p>
<p>Sounds simple, right? Yes, but only until you start documenting.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/bug-task.png" alt="Image" width="600" height="400" loading="lazy">
<em>A defect report</em></p>
<p>The bug report consists of the following sections: Identifier, Summary, Description, Steps to Reproduce, Reproducibility, Severity, Priority, Environment, and Attachments.</p>
<ul>
<li><strong>Identifier</strong>: Each software program problem is assigned a completely unique identifier that acts like a customized nameplate. This makes the QA documentation less complicated to navigate and allows verbal communication between the installer, tester, and project manager (PM).</li>
<li><strong>Summary:</strong> This is an opportunity to provide brief and informative answers to three basic questions: What was the problem? Where did the problem appear? Under what specific conditions did the problem appear?</li>
<li><strong>Explanation:</strong> Examine the failure log in more detail. Summarize the identified action (the result completed) and check it against the planned action (the predicted end result). Including a link to the app requirements of the software program can serve as a useful reference element.</li>
<li><strong>Reproduction method</strong> (STR): This phase should be considered as a step-by-step recipe for reproducing the defect. It should be strict and cover all the steps that caused the problem. Skipping critical steps can make it difficult for you to reproduce the problem and cause delays.</li>
<li><strong>Reproducibility:</strong> In this section, you clarify if the bug appears every time you follow the STR. You should use numbers to show approximate chances, for example, 7 times out of 10.</li>
<li><strong>Severity</strong>: Here you explain how much harm the bug may bring to the project. Essentially, this is a measure of the severity of the technical disruption that a bug will cause to the whole project. Remember that problems that are known to be minor can grow and cause you extreme problems throughout the software.</li>
<li><strong>Priority</strong>: Each error log assigns a problem priority that indicates its urgency. Common priorities are letters (A: highest priority, Z: highest priority), numbers (1: highest priority, 9: highest priority), or descriptive terms (high, medium, low).</li>
<li><strong>Environment</strong>: Specify the gadget or browser model in which the bug appeared. This will help you to put the problem in context and narrow down a valid cause.</li>
<li><strong>Attachments</strong>: If possible, enrich the documentation with screenshots, screen recordings, console log documents, and others. This will help to provide visual documentation of the error.</li>
</ul>
<p>My structure provides detailed information, so you can empower developers to effectively diagnose, address, and eliminate any software bugs. In this way, leading to more user-friendly and robust products. </p>
<p>Now, in the next section, we'll see some useful tips you can use for defect report writing.</p>
<h3 id="heading-useful-tips-for-defect-report-writing">Useful Tips for Defect Report Writing</h3>
<ol>
<li>Write a sufficient summary. It does not matter if it is long or short. What matters is that it should be clear.</li>
<li>Have a look at the summary and the description. Do they look pretty much the same? You must have forgotten to outline the expected and actual results in the description and to add the link to the requirements.</li>
<li>Capture the issue with the help of a screenshot. It may save you and the development team a lot of time. Sometimes one glance at the picture is just enough to understand the situation.</li>
<li>Before reporting the issue, try to reproduce it at least 3 times to be sure that it exists.</li>
<li>Report the issue ASAP and notify your project manager or product owner if the issue is major.</li>
<li>Check for grammar mistakes in your QA documentation so you're not taken down by the grammar police.</li>
<li>However comical it sounds, make sure that the issue is not a feature – review the documentation again!</li>
<li>Do not miss any important information in your Steps to Reproduce.</li>
</ol>
<h2 id="heading-submit-a-defect-report">Submit a Defect Report</h2>
<p>The final and one of the most important elements of QA documentation is the defect report. You may understand it covers the entire lifecycle of a problem, from its initial discovery to its final closure. </p>
<p>Let's now examine the key areas of this process:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/defect-report-lifecycle.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>a defect report lifecycle</em></p>
<p>We'll go over the defect report lifestyle piece by piece:</p>
<h3 id="heading-problem-reporting">Problem Reporting:</h3>
<p>This adventure begins with the careful compilation and submission of a report on the entire program. This serves as a roadmap for developers and provides a clear assessment of the problem.</p>
<h3 id="heading-triage-and-tasks">Triage and tasks:</h3>
<p>The task manager or technical lead takes on the role of gatekeeper at this stage. They carefully compare the files. If the file contains enough elements to work with, it is assigned to the developer and repaired. However, if the file is missing essential elements, it may be rejected for further improvement.</p>
<h3 id="heading-bug-fixing">Bug fixing:</h3>
<p>The assigned developer takes the initiative and works diligently to eliminate the annoying bug.</p>
<h3 id="heading-verification-and-completion">Verification and completion:</h3>
<p>Once the developer claims to have fixed the problem, it's your turn as QA. Carefully verify the fix by retesting the functionality in question. If everything works as it should, you are done. </p>
<p>The documentation has come to a happy end. Ideally, this will happen within a reasonable period of one to two weeks.</p>
<h3 id="heading-reboot-and-keep-going">Reboot and keep going:</h3>
<p>But it is not always that simple. If it is known that bugs are still being made in the validation system, there is no need to despair! </p>
<p>Re-open the bug documentation and send it to the developers for further attention. Sometimes the process of fixing bugs is repetitive and requires patience. But by being careful and effective, you can guarantee that all bug reports will eventually reach their final destination, resulting in a more polished and reliable software application product.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Quality Assurance is a process you simply cannot avoid. Each airplane prior to departure undergoes a technical check. If there is any issue, the aircraft is grounded until the problem is solved. The same goes for any software. </p>
<p>But QA documentation is not always "write and ignore". At some point in the software development lifecycle, QA documentation needs to be continually updated and improved as requirements change, new features are introduced, and feedback is received from deployment and production use.</p>
<p>There are also a growing number of styles that use synthetic intelligence and machine learning to partially automate the creation of QA documentation. </p>
<p>For example, natural language processing (NLP) is used to analyze requirements documents and generate draft control examples. Test bots can use NLP to interpret and routinely execute directed test cases. Predictive evaluation can also be used to identify the most dangerous areas of a software program that require more detailed control.</p>
<p>While these strategies are still new and not mature enough to replace human testers, they can help with growth and augment manual exploration, especially for large and complex builds. By making QA documentation a collaborative and ongoing hobby, your team can deliver better software faster and with fewer defects.</p>
<h3 id="heading-do-you-need-to-improve-the-quality-of-your-software">Do you need to improve the quality of your software?</h3>
<p>My company KeenEthics provides solid <a target="_blank" href="https://coventit.com/services/custom-software-development">development and quality assurance services</a>. In case you need an estimate for a similar project, feel free to <a target="_blank" href="https://coventit.com/contact-us">get in touch</a><em>.</em> </p>
<p>If you have enjoyed the article, you should continue with <a target="_blank" href="https://coventit.com/blog/How-IT-Outsourcing-Saves-Costs">How IT Outsourcing Saves Costs for Your Company</a> and <a target="_blank" href="https://coventit.com/blog/risks-of-it-outsourcing">Avoiding Pitfalls in IT Outsourcing: Tips for Minimizing Risks</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Become a Quality Assurance Engineer – QA Engineer Career Guide ]]>
                </title>
                <description>
                    <![CDATA[ A Quality Assurance (QA) Engineer is someone who tests software products throughout the whole development process. They ensure that the product meets high quality standards before releasing it to the public. But how do you become a QA Engineer? In th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-become-a-quality-assurance-engineer-qa-engineer-career-guide/</link>
                <guid isPermaLink="false">66b8d96857c651c38343a9a0</guid>
                
                    <category>
                        <![CDATA[ career advice ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jessica Wilkins ]]>
                </dc:creator>
                <pubDate>Mon, 16 May 2022 15:33:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/thisisengineering-raeng-1oYSrlQrpY4-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A Quality Assurance (QA) Engineer is someone who tests software products throughout the whole development process. They ensure that the product meets high quality standards before releasing it to the public.</p>
<p>But how do you become a QA Engineer? In this article, I will talk about the qualifications and process for becoming a QA engineer.</p>
<h2 id="heading-what-is-quality-assurance-and-quality-control">What is Quality Assurance and Quality Control?</h2>
<p>When a product is being built, stakeholders have expectations and requirements. It is important that there is a process put in place to ensure that those high quality standards are being adhered to and mistakes in the product development are spotted and reported.</p>
<p>Quality Assurance focuses more on proactive processes while Quality Control focuses more on reactive corrections that need to be made. </p>
<p>Quality control also focuses on inspection and testing whereas Quality Assurance involves documentation, audits, and management.</p>
<h2 id="heading-core-skills-needed-for-becoming-a-good-qa-engineer">Core skills needed for becoming a good QA engineer</h2>
<h3 id="heading-attention-to-detail">Attention to detail</h3>
<p>The role of a QA engineer involves being detail-oriented and thorough in order to spot issues or discrepancies in quality standards set for the product.</p>
<h3 id="heading-good-communication">Good communication</h3>
<p>QA engineers will be communicating with stakeholders, management, and developers for the product. Effective and clear communication between all parties involved is really important for the development process of a product.</p>
<h3 id="heading-good-time-management">Good time management</h3>
<p>Since a QA engineer will have to balance multiple tasks throughout the day, it is important to have strong time management skills to ensure that you stay productive and are able to meet your deadlines.</p>
<h3 id="heading-problem-solving-skills">Problem solving skills</h3>
<p>Throughout the life cycle of a product, issues will arise. It is important that QA engineers have strong problem solving skills and are able to develop a plan to solve those issues.</p>
<h3 id="heading-strong-listening-skills">Strong listening skills</h3>
<p>A good QA engineer not only needs to be able to communicate but also listen to their development team, management, and stakeholders to ensure the successful launch of the product.</p>
<h3 id="heading-the-ability-to-write-a-test-plan">The ability to write a test plan</h3>
<p>A test plan is a document detailing the objectives and testing processes that will be applied to the software product. QA engineers will work with other developers and stakeholders to develop this testing strategy.</p>
<h3 id="heading-an-understanding-of-test-automation-tools-and-manual-testing-practices">An understanding of test automation tools and manual testing practices</h3>
<p>It is helpful for QA engineers to be familiar with different automated testing tools like Selenium. They will also need to know how to effectively manually test products in order to identify bugs.</p>
<h3 id="heading-strong-understanding-of-the-software-development-life-cycle">Strong understanding of the Software Development Life Cycle</h3>
<p>A good QA engineer should understand the full life cycle of software products in order to effectively plan and test them.</p>
<p>Here are the 7 phases of the <a target="_blank" href="https://www.freecodecamp.org/news/get-a-basic-understanding-of-the-life-cycles-of-software-development/">Software Development Life Cycle</a>:</p>
<ol>
<li>Planning Stage</li>
<li>Analysis Stage</li>
<li>Design Stage</li>
<li>Software Development Stage</li>
<li>Software Testing Stage</li>
<li>Implementation and Integration</li>
<li>Operations and Maintenance Stage</li>
</ol>
<h2 id="heading-do-you-need-to-learn-how-to-code-become-a-qa-engineer">Do you need to learn how to code become a QA engineer?</h2>
<p>Learning programming fundamentals can help QA engineers build automated test suites to save time on manual testing and provide a better understanding of the development implementations by the software developers.</p>
<p>Some widely used programming languages to learn would be Java, C#, JavaScript, and Python.</p>
<p>Choose one language to learn to get an understanding of the programming fundamentals.</p>
<h2 id="heading-do-you-need-a-computer-science-degree-to-become-a-qa-engineer">Do you need a Computer Science degree to become a QA engineer?</h2>
<p>Having a Computer Science degree can help you when it comes to finding your first Quality Assurance job because a lot of employers still prefer a degree. If you have the time and money to pursue that path, that can be a viable option.</p>
<p>Other options would be to go to a bootcamp or teach yourself through online resources. If you are considering a bootcamp, please read through this <a target="_blank" href="https://www.freecodecamp.org/news/coding-bootcamp-handbook/">helpful resource</a> first.</p>
<h2 id="heading-do-you-need-certifications-to-become-a-good-qa-engineer">Do you need certifications to become a good QA engineer?</h2>
<p>QA certifications can help boost your resume and knowledge base. A lot of these certifications do require that you have degree from an accredited university or a few years of experience.</p>
<p>Here are some QA certifications you can look into:</p>
<ul>
<li>Certified Associate in Software Testing (CAST)</li>
<li>Certified Test Engineer (CSTE)</li>
<li>Certified Software Quality Analyst (CSQA)</li>
</ul>
<h2 id="heading-how-to-get-a-job-as-a-qa-engineer">How to get a job as a QA engineer</h2>
<p>Once you have learned programming, testing, and QA fundamentals then you can start looking for junior level positions. Make sure to build out a strong résumé and prepare for the QA interview questions using free online interview guides.</p>
<p>If you are self taught, it would help to have a little bit of experience through small contract work. If you are in a degree program, students will have access to internship opportunities and other career resources.</p>
<h2 id="heading-salaries-for-qa-engineers">Salaries for QA engineers</h2>
<p>Salaries for QA engineers will range depending on experience and location. The average base US salary according to <a target="_blank" href="<https://www.payscale.com/research/US/Job=Quality_Assurance_(QA)_Engineer/Salary>">payscale</a> is $72,000.</p>
<p>I hope you enjoyed this article and best of luck on your software journey.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test Your Apps using Jest, Testing Library, Cypress, and Supertest ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this article we're going to talk about testing. I'll give you a good overview of what testing is and an introduction of how you can implement it on your JavaScript projects. We'll use four very popular tools – Jest, Testing library, C... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/test-a-react-app-with-jest-testing-library-and-cypress/</link>
                <guid isPermaLink="false">66d45f22264384a65d5a9528</guid>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react testing library ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ German Cocca ]]>
                </dc:creator>
                <pubDate>Mon, 25 Apr 2022 17:13:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/pexels-rodolfo-clix-1366942.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this article we're going to talk about testing. I'll give you a good overview of what testing is and an introduction of how you can implement it on your JavaScript projects. We'll use four very popular tools – Jest, Testing library, Cypress and Supertest.</p>
<p>First we're going to talk about what testing is, why is it a good idea to test our code, and the different kinds of tests that can be implemented.</p>
<p>Then we're going to introduce each of the tools we will be using, and finally we'll give practical examples for vanilla JS code, a front-end React app, and a back-end Node app.</p>
<p>Andiamo via!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-testing-and-why-is-it-valuable">What is testing and why is it valuable</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-different-types-of-tests">Different types of tests</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-manual-vs-automated-testing">Manual vs Automated testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-functional-vs-non-functional-testing">Functional vs Non-functional testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-unit-vs-integration-testing-vs-end-to-end-testing">Unit vs Integration vs End-to-end testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-white-box-vs-black-box-vs-grey-box-testing">White box vs Black box vs Grey box testing</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-test">When to test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-our-toolset">Our toolset</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-jest">What is Jest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-testing-library">What is Testing library</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-cypress">What is Cypress</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-supertest">What is Supertest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tools-roundup">Tools roundup</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-vanilla-js-code">How to test vanilla JS code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-front-end-react-app-with-jest-and-react-testing-library">How to test a front-end React app with Jest and React testing library</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-front-end-react-app-with-cypress">How to test a front-end React app with Cypress</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-back-end-node-app">How to test a back-end Node app</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrap-up">Wrap up</a></p>
</li>
</ul>
<h1 id="heading-what-is-testing-and-why-is-it-valuable">What is Testing and Why is it Valuable</h1>
<p>Testing is the practice of checking if a piece of software runs as expected. This is often recognized as QA or quality assurance, and aims to reduce to a bare minimum the amount of bugs that get to production.</p>
<p>We test software to identify errors, gaps or missing requirements and fix those things before shipping code to production.</p>
<p>Testing our code thoroughly improves our project's reliability, saves us later bug-fixing time and hence reduces costs, and improves the chance of our customer being fully satisfied with our product.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/BvIJ1M5-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=u6QfIXgjwGQ&amp;t=6s">Here's a nice short video by Fireship</a> introducing some of the concepts we'll talk about later.</p>
<h1 id="heading-different-types-of-tests">Different Types of Tests</h1>
<p>Testing practices can be classified in different types according to many factors. Personally I think there's a lot of mumbo jumbo about this topic, with hundreds of terms that often refer to very similar things. So let's keep it simple and review only the most popular terms and what they mean.</p>
<p>This will help clarify the many ways in which a software can be tested and better understand the tools we're going to present later on.</p>
<h3 id="heading-manual-vs-automated-testing">Manual vs Automated testing</h3>
<p>Depending on the tools we use to test our software, we can classify testing into <strong>manual</strong> or <strong>automated testing</strong>.</p>
<p><strong>Manual testing</strong> is the practice of "clicking around" and manually checking all the features our product has, simulating what an actual user would do.</p>
<p><strong>Automated testing</strong> is done through code, writing programs that check how our application runs.</p>
<p>There're many testing frameworks and libraries we can use for this. When it comes to functional testing (we're going to see what that means in a sec), most libraries work in a similar way:</p>
<ul>
<li><p>First we <strong>define</strong> what piece of code we want to test.</p>
</li>
<li><p>Then we provide that piece of code some sort of <strong>input</strong> or execute an <strong>action</strong> on it.</p>
</li>
<li><p>Then we define what that piece of code <strong>should do</strong> given the input/action we performed.</p>
</li>
<li><p>And finally we will <strong>compare</strong> what that piece of code actually did against what we said it should do.</p>
</li>
</ul>
<p>If it did what we said it should, the test passed. If it didn't, it failed.</p>
<h3 id="heading-functional-vs-non-functional-testing">Functional vs Non-functional testing</h3>
<p><strong>Functional</strong> testing refers to the actual <strong>features of our product</strong>. For example, if we have a blog platform, functional testing should assure the users can create new articles, edit those articles, browse through articles written by other people, and so on.</p>
<p><strong>Non-functional</strong> testing refers to anything that's <strong>not strictly related to the core features</strong> of our product. And that again can be classified into different categories, for example:</p>
<ul>
<li><p><strong>Stress testing</strong> checks how infrastructure responds to heavy usage.</p>
</li>
<li><p><strong>Security testing</strong> checks if an application is vulnerable to common hacking attacks.</p>
</li>
<li><p><strong>Accessibility testing</strong> checks if an application is coded in a way that is accessible for people with different disabilities.</p>
</li>
</ul>
<h3 id="heading-unit-vs-integration-testing-vs-end-to-end-testing">Unit vs Integration testing vs End-to-end testing</h3>
<p>Another way to classify testing is depending how broad or comprehensive it is.</p>
<p><strong>Unit testing</strong> aims to test individual functions, methods or small chunks of code in an independent way. In unit testing, small pieces of code are checked in an isolated way.</p>
<p><strong>Integration testing</strong> checks how individual pieces of code interact with each other and work together. In integration testing, we put pieces together and see if they interact correctly.</p>
<p><strong>End-to-end testing</strong>, also known as E2E, executes programs in a simulated environment that emulates actual user behavior. Having a website as an example, our code would open in an actual browser and all the features would be executed in the same way a user would use them. E2E testing is a lot like manual testing in that sense, but fully automated.</p>
<p>E2E testing is the most broad or comprehensive type of these three, as it evaluates whole features and behaviors, not specific parts of our code.</p>
<h3 id="heading-white-box-vs-black-box-vs-grey-box-testing">White box vs Black box vs Grey box testing</h3>
<p>The last classification we're going to see depends on how much our tests focus on implementation details or user experience.</p>
<p>Let's say we have a simple website with a button that, when it gets clicked, it opens a modal. In our code, the button has a click event listener that executes a function. That function changes the CSS class of our modal HTML element, and that gets the modal rendered in the screen.</p>
<p>We talk about "<strong>white box</strong>" testing when we test <strong>implementation details</strong>. Following the example, under this paradigm we could test that the button click executes the corresponding function, and that after the function execution, the CSS class of our modal element is changed accordingly.</p>
<p>Another way to do this is to forget about implementation all together and just check if the modal is rendered after the button click. We don't care what the CSS class is, or if the corresponding function is executed or not. We just focus on testing <strong>what the user should perceive.</strong> That's "<strong>black box</strong>" testing.</p>
<p>And, as you may have guessed, "grey box" testing is just a combination of the previous two.</p>
<p>One last thing to mention here is that these different types of tests aren't necessarily mutually exclusive. I mean, they can and often are implemented at the same time on the same projects.</p>
<p>It's very common to have both manual and automated testing, functional and non-functional testing, unit and E2E testing ... The idea will always be to try to anticipate and solve the greatest possible number of problems in reasonable time and effort.</p>
<h1 id="heading-when-to-test">When to Test</h1>
<p>This may seem like a simple question at first, but there are actually different approaches to this, too.</p>
<p>Some people like to test their app once it's been fully developed. Others like to write tests at the same time they code the application, and test each feature as it's being developed.</p>
<p>Others like to write tests first before anything else, defining in this way the minimum requirements for the program to accomplish. And then they code the app in a way that passes those tests as fast as possible (this is called <a target="_blank" href="https://en.wikipedia.org/wiki/Test-driven_development">test driven development or TDD</a>).</p>
<p>Once you have an app or a whole feature developed, and you have a test suite in place (a test suite is a group of tests that check a particular feature or an entire app), another common practice is to run your tests each time you make any kind of modification to the codebase, to verify nothing gets broken.</p>
<p>Lastly, if you have a <a target="_blank" href="https://en.wikipedia.org/wiki/CI/CD">CI/CD</a> system in place, it's common to automate the execution of tests before any deployment. So that if any test fails, the deployment is stopped and some kind of alert is dispatched (which of course is always better than seeing your app catch fire on prod 🔥😱).</p>
<p>Same as with test types, it's common to test applications at different times. Each company normally has its own testing schedule or practice to follow, tailored to their needs.</p>
<h1 id="heading-our-toolset">Our Toolset</h1>
<p>Ok, now that we have a clearer idea of what testing is and the types of tests we can perform, let's review the tools we're going to use in our examples.</p>
<p>As mentioned before, there are a lot of different libraries to choose to run our tests. I chose these four because they are some of the most popular when it comes to JavaScript apps, but know there are more options out there. I'll be naming alternatives for most of the tools we'll use in case you'd like to investigate more. 😉</p>
<h2 id="heading-what-is-jest">What is Jest</h2>
<p><a target="_blank" href="https://jestjs.io/">Jest</a> is a JavaScript test-runner. A test-runner is a piece of software that allows you to run tests to evaluate your app. It's an open-source project maintained by Meta (formerly Facebook), and was first open-sourced in 2014.</p>
<p>Side comment: Every time I say "test runner" I picture this. Am I the only one? 🤔</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/8gTI-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test runner, not Blade runner!</em></p>
<p>Anyway...you can use Jest in projects that use <a target="_blank" href="https://babeljs.io/">Babel</a>, <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a>, <a target="_blank" href="https://nodejs.org/en/">Node.js</a>, <a target="_blank" href="https://reactjs.org/">React</a>, <a target="_blank" href="https://angular.io/">Angular</a>, <a target="_blank" href="https://vuejs.org/">Vue.js</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a> and other technologies too. You can install Jest through NPM just like any library and it requires very little configuration to start off.</p>
<p>Jest comes installed by default when setting up React apps with <a target="_blank" href="https://create-react-app.dev/">create-react-app</a>.</p>
<p>Jest is often also called a testing framework, as it comes with many other built-in features besides just running tests (which is not the case with all test runners). Some of those features are:</p>
<ul>
<li><p><strong>Assertion library:</strong> Jest comes with a lot of built-in functions and methods you can use to assert your code (asserting basically means checking if a piece of code behaves like it's expected).</p>
</li>
<li><p><strong>Snapshot testing:</strong> Jest allows you to use snapshots, which are a way of capturing a large object and storing it in memory so you can later on compare it with something else.</p>
</li>
<li><p><strong>Code coverage:</strong> Jest allows you to get code coverage reports of your tests. These reports show what percentage of your code is currently being tested, and you can even see the exact lines of code that aren't currently being covered.</p>
</li>
<li><p><strong>Mocking library:</strong> Jest also works like a mocking library in the sense that it allows you to mock data (like a function or a module) and use that in your tests.</p>
</li>
</ul>
<p>Some well known alternatives to Jest are <a target="_blank" href="https://mochajs.org/">Mocha</a>, <a target="_blank" href="https://jasmine.github.io/">Jasmine</a>, and <a target="_blank" href="https://karma-runner.github.io/latest/index.html">Karma</a>.</p>
<p>Here's <a target="_blank" href="https://www.youtube.com/watch?v=SyHzgcFefBk">a nice little video</a> explaining what Jest is.</p>
<h2 id="heading-what-is-testing-library">What is Testing Library?</h2>
<p>Testing library is not a test runner, but a set of utilities that will work together with a test runner like Jest or Mocha. This utilities are tools we can use to test our code easily and with a deeper focus on user experience (black box testing).</p>
<p>Testing library was developed by <a target="_blank" href="https://kentcdodds.com/">Kent C Dodds</a> (who also happens to be one of the best JS teachers on earth, so I recommend that you follow him).</p>
<p>Quoting <a target="_blank" href="https://testing-library.com/">the official docs:</a></p>
<blockquote>
<p><em>"The Testing Library family of libraries is a very light-weight solution for testing without all the implementation details.</em></p>
<p><em>The main utilities it provides involve querying for nodes similarly to how users would find them. In this way, testing-library helps ensure your tests give you confidence in your UI code."</em></p>
</blockquote>
<p>In plain English, with the testing library we can test UI elements (like a paragraph, a button, a div...) instead of testing the code responsible for rendering the UI.</p>
<p>The principle behind the library is:</p>
<blockquote>
<p><em>"The more your tests resemble the way your software is used, the more confidence they can give you."</em></p>
</blockquote>
<p>... and that's exactly what we mean by "black box" testing. 😉</p>
<p>The testing library is actually a <strong>set of libraries</strong>, each created to achieve the same objective but adapted to work with different technologies such as React, Angular, Vue, Svelte, React Native and more... That's why you might hear "React-testing-library" or "Vue-testing-library". It's the same thing but adapted to work with different technologies.</p>
<p>React-testing-library comes installed by default when setting up React apps with <a target="_blank" href="https://create-react-app.dev/">create-react-app</a>.</p>
<p>An alternative to testing library is <a target="_blank" href="https://enzymejs.github.io/enzyme/">Enzyme</a> (a UI testing set of utilities developed by Airbnb).</p>
<h2 id="heading-what-is-cypress">What is Cypress?</h2>
<p>Cypress is an open source test-runner that allows you to execute your projects in an automated browser, in the same way a user would.</p>
<p>With Cypress, we can program what the browser will do (like visit a URL, click a button, complete and submit a form...) and check that each action is matched with the corresponding response.</p>
<p>What's sweet about this is that the testing resembles A LOT to what the user will experience. And since the whole point of making software is the user, the closer we are to their perspective, the closer we should be to catching the most meaningful bugs in our code. (Plus it's really cool to see an automated browser go through your entire app in just a few seconds... 🤓)</p>
<p>Another nice feature of Cypress is "time travel". On Cypress's automated browser we can see all the test's we've written, and simply hover over them to see a graphical snapshot of its result. It's a very useful thing to better understand what's breaking and when.</p>
<p>Even though it can be used for unit and integration testing, Cypress is mostly used for end-to-end testing as it can easily evaluate complete features in a matter of seconds.</p>
<p>You can use Cypress to test anything that runs in a browser, so you can easily implement it on React, Angular, Vue, and so on.</p>
<p>Unlike Jest and React-Testing-Library, Cypress doesn't come pre-installed with create-react-app. But we can easily install it with NPM or your package manager of choice.</p>
<p>Some alternatives to Cypress are <a target="_blank" href="https://www.selenium.dev/">Selenium</a> and <a target="_blank" href="https://pptr.dev/">Puppeteer</a>.</p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=BQqzfHQkREo">Here's a sweet video by Fireship explaining what Cypress is and how it works.</a></p>
<p>Side comment: ...and every time I talk about Cypress <a target="_blank" href="https://www.youtube.com/watch?v=BV3CYz34ziE">this plays in my mind</a>. 😎</p>
<h2 id="heading-what-is-supertest">What is Supertest?</h2>
<p><a target="_blank" href="https://github.com/visionmedia/supertest">Supertest</a> is a library that simulates HTTP requests. It's super handy to test back-end Node apps together with Jest (as we will see in the coming examples).</p>
<h3 id="heading-tools-roundup">Tools roundup</h3>
<p>As a quick round-up about this topic:</p>
<ul>
<li><p>Jest is the library that we'll use to write and run tests for JavaScript.</p>
</li>
<li><p>Testing library works together with Jest, and provides us with functions and methods to test the UI directly, forgetting about the code behind it.</p>
</li>
<li><p>Cypress runs your app in a simulated browser and checks if actions performed in the UI respond as expected.</p>
</li>
<li><p>Supertest is a library that mocks HTTP requests and it can be used together with Jest to test back-end apps.</p>
</li>
</ul>
<p>Now let's begin with the fun part ...</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/giphy-2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Let the testing begin!!</em></p>
<h1 id="heading-how-to-test-vanilla-js-code">How to Test Vanilla JS Code</h1>
<p>Ok, let's start by testing some simple vanilla JS code. The idea here is to see how we can implement Jest in our project and learn the basics of how it works.</p>
<p>Let's start by creating a new directory in our machine and creating a Node app with <code>npm init -y</code>. Then install Jest by running <code>npm i -D jest</code> (<code>-D</code> saves it as a development dependency).</p>
<p>Now you should see something like this in your <code>package.json</code> file: <code>"devDependencies": { "jest": "^27.5.1" }</code> .</p>
<p>And speaking about it, in your <code>package.json</code>, replace your <code>test</code> script with <code>"test": "jest"</code>. This will allow us to later run our tests by running <code>npm test</code>. ;)</p>
<p>Your entire <code>package.json</code> file should look something like this:</p>
<pre><code class="lang-plaintext">{
  "name": "vanillatesting",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "jest": "^27.5.1"
  }
}
</code></pre>
<p>Cool, we're all set to write some JS we can actually test! Create an <code>index.js</code> file and put this code in it:</p>
<pre><code class="lang-plaintext">// index.js
function isPalindrome(string) {
    // O(n)
    // Put a pointer at each extreme of the word and iterate "inwards"
    // At each iteration, check if the pointers represent equal values
    // If this condition isn't accomplished, the word isn't a palindrome
    let left = 0
    let right = string.length-1

    while (left &lt; right) {
        if (string[left] === string[right]) {
            left += 1
            right -= 1
        }
        else return false
    }

    return true
}
</code></pre>
<p>This function is a <a target="_blank" href="https://en.wikipedia.org/wiki/Palindrome">palindrome</a> checker. It receives a string as parameter, and returns <code>true</code> if the string is a palindrome and <code>false</code> if it's not. (This is a classic technical interview question btw, but that's stuff for another article.🤫)</p>
<p>See that we're exporting the function too. Side comment: If you'd like to know more about this and how JS modules work, I recently wrote <a target="_blank" href="https://www.freecodecamp.org/news/modules-in-javascript">an article</a> about it.</p>
<p>Great, so now let's test this function and see if it works as expected. Let's create a file called <code>index.test.js</code>.</p>
<p>This file is where we'll write our tests. The suffix we're using (<code>.test.js</code>) is important here, as Jest will automatically identify the <code>.test</code> files and execute them when we order Jest to test our project.</p>
<p>Jest also identifies files with the <code>.spec</code> suffix, like <code>index.spec.js</code> (for "specification", which refers to the requirements of your project). Personally I prefer <code>.test</code> as it feels more explicit to me, but both work the same.</p>
<p>Now let's write our first tests! Put this within your <code>index.test.js</code> file.</p>
<pre><code class="lang-plaintext">// index.test.js
isPalindrome = require('./index.js')

test('neuquen is palindrom', () =&gt; {
    expect(isPalindrome("neuquen")).toBe(true)
})

test('bariloche is not palindrom', () =&gt; {
    expect(isPalindrome("bariloche")).toBe(false)
})
</code></pre>
<p>Let's recap what we're actually doing:</p>
<ol>
<li><p>Require the function we want to test: <code>isPalindrome = require('./index.js')</code></p>
</li>
<li><p>The <code>test()</code> function is provided by Jest and within it we will put the code we want Jest to execute.</p>
</li>
<li><p><code>test()</code> takes two parameters. The first is a test description, which is a distinctive name that will show on our console when the test is run. We'll see an example in a sec.</p>
</li>
<li><p>The second parameter is a callback, which contains the actual testing code.</p>
</li>
<li><p>Within this callback we're calling the <code>expect()</code> function (also provided by Jest). <code>expect()</code> takes our function as parameter, which itself is receiving a parameter we made up.</p>
</li>
<li><p>Last, we chain the <code>.toBe()</code> function (provided by Jest too) and as parameter we pass it the value we expect <code>isPalindrome()</code> to return for each case. ("neuquen" is a palindrome so our function should return <code>true</code>, and "bariloche" is not, so it should return <code>false</code>.)</p>
</li>
</ol>
<p>One of the things I like the most about Jest is how easy it is to set it up. Another thing I like a lot is how self explanatory its syntax is. Notice that we can easily understand what our tests will evaluate by just reading them.👌</p>
<p>Now let's try this! If we run <code>npm test</code> in our console, we should get the following:</p>
<pre><code class="lang-plaintext">// console
&gt; jest PASS 
./index.test.js
✓ neuquen is palindrom (1 ms)
✓ bariloche is not palindrom

Test Suites: 1 passed, 1
total Tests:       2 passed, 2
total Snapshots:   0
total Time:        0.244 s
Ran all test suites.
</code></pre>
<p>Congratulations, you just passed your first Jest test ever.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/mr-miyagi-nod-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/lets-get-this-party-started-yeah-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To see how a failing test looks too, let's change our function by editing the <code>return</code> lines.</p>
<pre><code class="lang-plaintext">// index.js
function isPalindrome(string) {
    // O(n)
    // Put a pointr at each extreme of the word and iterate "inwards"
    // At each iteration, check if the pointers represent equal values
    // If this condition isn't accomplished, the word isn't a palindrome
    let left = 0
    let right = string.length-1

    while (left &lt; right) {
        if (string[left] === string[right]) {
            left += 1
            right -= 1
        }
        else return 1
    }

    return 2
}
</code></pre>
<p>Now you should get something like this:</p>
<pre><code class="lang-plaintext">// console
&gt; vanillatesting@1.0.0 test
&gt; jest

 FAIL  ./index.test.js
  ✕ neuquen is palindrom (4 ms)
  ✕ bariloche is not palindrom

  ● neuquen is palindrom

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

    Expected: true
    Received: 2

      3 | // describe('isPalindrome function', () =&gt; {
      4 |   test('neuquen is palindrom', () =&gt; {
    &gt; 5 |     expect(isPalindrome("neuquen")).toBe(true)
        |                                     ^
      6 |   })
      7 |
      8 |   test('bariloche is not palindrom', () =&gt; {

      at Object.&lt;anonymous&gt; (index.test.js:5:37)

  ● bariloche is not palindrom

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

    Expected: false
    Received: 1

       7 |
       8 |   test('bariloche is not palindrom', () =&gt; {
    &gt;  9 |     expect(isPalindrome("bariloche")).toBe(false)
         |                                       ^
      10 |   })
      11 | // })
      12 |

      at Object.&lt;anonymous&gt; (index.test.js:9:39)

Test Suites: 1 failed, 1 total
Tests:       2 failed, 2 total
Snapshots:   0 total
Time:        0.28 s, estimated 1 s
Ran all test suites.
</code></pre>
<p>See that you get a nice description of what tests failed and at which point they failed. In our case they failed when we asserted (checked) the return values.</p>
<p>This is very useful and we should always pay attention to these descriptions, as some times our tests may fail because they're not written correctly. And we don't normally write tests for our tests, yet... 😅 So when you see a failing test, first check that it's working as expected and then go review your actual code.</p>
<p>Now let's add and test another function to show some more Jest features:</p>
<pre><code class="lang-plaintext">// index.js
function twoSum(nums, target) {
    // O(n)
    // Iterate the array once
    // At each iteration, calculate the value needed to get to the target, which is target - currentValue
    // If the neededValue exists in the array, return [currentValue, neededValue], else continue iteration
    for (let i = 0; i &lt; nums.length; i++) {
        const neededNum = target - nums[i]
        if (nums.indexOf(neededNum) !== -1 &amp;&amp; nums.indexOf(neededNum) !== i) return [nums[i], nums[nums.indexOf(neededNum)]]
    }
    return false
}

module.exports = { isPalindrome, twoSum }
</code></pre>
<p>This is another classic interview question. The function takes two parameters, an array of numbers and a target value number. What it does is to identify if there are two numbers in the array that add up to the second parameter value. If the two values exist in the array, it returns them in an array, and if they don't, it returns false.</p>
<p>Now let's write some tests for this:</p>
<pre><code class="lang-plaintext">({ isPalindrome, twoSum } = require('./index.js'))

...

test('[2,7,11,15] and 9 returns [2, 7]', () =&gt; {
    expect(twoSum([2,7,11,15], 9)).toEqual([2,7])
})

test('[3,2,4] and 6 returns [2, 4]', () =&gt; {
    expect(twoSum([3,2,4], 6)).toEqual([2,4])
})

test('[3,2,4] and 10 returns false', () =&gt; {
    expect(twoSum([3,2,4], 10)).toBe(false)
})
</code></pre>
<p>See that the structure is almost the same, except we're using a different <strong>matcher</strong> in two of the tests, <code>toEqual()</code>.</p>
<p><strong>Matchers</strong> are the functions Jests provides us with to evaluate values. There are many types of matchers that can be used for many different occasions.</p>
<p>For example, <code>.toBe()</code> is used to evaluate primitives like strings, numbers, or booleans. <code>toEqual()</code> is used to evaluate objects (which covers pretty much everything else in Javascript).</p>
<p>If you need to compare the return value with a number you could use <code>.toBeGreaterThan()</code> or <code>toBeGreaterThanOrEqual()</code> and so on...</p>
<p>To see a full list of the available matchers, <a target="_blank" href="https://jestjs.io/docs/using-matchers">check the docs</a>.</p>
<p>If we run our tests now, we will get the following:</p>
<pre><code class="lang-plaintext">&gt; vanillatesting@1.0.0 test
&gt; jest

 PASS  ./index.test.js
  ✓ neuquen is palindrom (2 ms)
  ✓ bariloche is not palindrom
  ✓ [2,7,11,15] and 9 returns [2, 7] (1 ms)
  ✓ [3,2,4] and 6 returns [2, 4]
  ✓ [3,2,4] and 10 returns false (1 ms)

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        0.256 s, estimated 1 s
Ran all test suites.
</code></pre>
<p>That's cool, but our tests results look a bit messy. And as our tests suite grows, it will probably be harder to identify each separate result.</p>
<p>To help us with this, Jest provides us with a <code>describe()</code> function, which we can use to group tests together and show results in a more schematic way. We can use it like this:</p>
<pre><code class="lang-plaintext">({ isPalindrome, twoSum } = require('./index.js'))

describe('isPalindrome function', () =&gt; {
  test('neuquen is palindrom', () =&gt; {
    expect(isPalindrome("neuquen")).toBe(true)
  })

  test('bariloche is not palindrom', () =&gt; {
    expect(isPalindrome("bariloche")).toBe(false)
  })
})

describe('twoSum function', () =&gt; {
  test('[2,7,11,15] and 9 returns [2, 7]', () =&gt; {
    expect(twoSum([2,7,11,15], 9)).toEqual([2,7])
  })

  test('[3,2,4] and 6 returns [2, 4]', () =&gt; {
    expect(twoSum([3,2,4], 6)).toEqual([2,4])
  })

  test('[3,2,4] and 10 returns false', () =&gt; {
    expect(twoSum([3,2,4], 10)).toBe(false)
  })
})
</code></pre>
<p>The first parameter is the description we want to show for the given group of tests, and the second is a callback that contains our tests. Now if we run <code>npm test</code> again, we get this 😎:</p>
<pre><code class="lang-plaintext">// console
&gt; vanillatesting@1.0.0 test
&gt; jest

 PASS  ./index.test.js
  isPalindrome function
    ✓ neuquen is palindrom (2 ms)
    ✓ bariloche is not palindrom
  twoSum function
    ✓ [2,7,11,15] and 9 returns [2, 7] (1 ms)
    ✓ [3,2,4] and 6 returns [2, 4]
    ✓ [3,2,4] and 10 returns false

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        0.216 s, estimated 1 s
Ran all test suites.
</code></pre>
<h1 id="heading-how-to-test-a-front-end-react-app-with-jest-and-react-testing-library">How to Test a Front-end React App with Jest and React Testing Library</h1>
<p>Now that we know the basics of Jest, let's hop on to see how we can combine it with Testing library to test a React app.</p>
<p>For this we're going to use a dead simple example. Just a page with random text, a button that toggles another piece of text, a text input, and a button that toggles the rendering of the input.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Recording-2022-04-23-at-21.11.24.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Take into account we'll be using <a target="_blank" href="https://create-react-app.dev/">create-react-app</a> to create this app (which has Jest and Testing library installed by default). If you're not using create-react-app, you might need to install both libraries and add some extra config.</p>
<p>We're not going to see any React code here, we're just going to focus on the tests.</p>
<p>The folder structure of our project is the following:</p>
<pre><code class="lang-plaintext">&gt; src
    &gt; components
        - About.jsx
    - App.jsx
    - Index.js
    - setupTests.js
</code></pre>
<p>The <code>setupTests.js</code> file is important here. It's created by default with create-react-app with this content:</p>
<pre><code class="lang-plaintext">// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
</code></pre>
<p>It globally imports the <code>jest-dom</code> library provided by Testing library, which gives us additional Jest matchers we can use to test the DOM (like <code>toHaveTextContent(), toBeInTheDocument()</code>, etc).</p>
<p>We're going to see examples in a bit, but know that some of the functions and matchers we'll use come from here.</p>
<p>Regarding our tests files, the common practice is to have a different test file for each component we're testing.</p>
<p>Regarding where to place them, two common practices are to have them all together in a single folder, like <code>__tests__</code> or similar, or to have each test file in the same folder as the component it's testing.</p>
<p>I prefer the later as I'll often be hopping from the component code to the test code, and it's nice to have them nearby. But trully it doesn't matter. As long as we use the <code>.test</code> or <code>.spec</code> suffixes, Jest will identify and run the files anyway.</p>
<p>Having created our tests files, our folder structure should look like this:</p>
<pre><code class="lang-plaintext">&gt; src
    &gt; components
        - About.jsx
        - About.test.jsx
    - App.jsx
    - Index.js
    - setupTests.js
</code></pre>
<p>Cool! Let's start by testing our <code>About</code> component.</p>
<p>First lets test that it's rendering correctly, like this:</p>
<pre><code class="lang-plaintext">// About.test.jsx
import { render, screen } from '@testing-library/react'
import About from './About'

describe('About', () =&gt; {

  test('About renders correctly', () =&gt; {
    render( &lt;About/&gt; )
    expect(screen.getByText("I'm the about page!")).toBeInTheDocument()
  })

})
</code></pre>
<ul>
<li>See that we start by importing two things from Testing library: <code>import { render, screen } from '@testing-library/react'</code>.</li>
</ul>
<p>The <code>render</code> function takes a React component as a parameter and it will render it so we can test it.</p>
<p><code>screen</code> is an object that comes with lots of queries we can use to test the UI directly, skipping implementation details and focusing on what the user will actually see.</p>
<ul>
<li><p>Then we import our <code>About</code> component: <code>import About from './About'</code></p>
</li>
<li><p>We use the <code>describe</code> and <code>test</code> Jest functions previously mentioned.</p>
</li>
<li><p>We render the <code>About</code> component: <code>render( &lt;About/&gt; )</code></p>
</li>
<li><p>We use the <code>expect</code> Jest function, and as a parameter we use the <code>screen</code> object provided by Testing library. We use its <code>getByText</code> query, which scans the React component for the text we pass as parameter.</p>
</li>
<li><p>To end, we use the Testing library's <code>.toBeInTheDocument()</code> matcher, which just checks if the previous query result is being rendered.</p>
</li>
</ul>
<p>Then we can test that the "Switch state" toggle button works correctly, like this:</p>
<pre><code class="lang-plaintext">// About.test.jsx
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import About from './About'

describe('About', () =&gt; {

  ...

  test('Switch state works correctly', async () =&gt; {
    render( &lt;About/&gt; )

    expect(screen.getByText("It's on!")).toBeInTheDocument()
    userEvent.click(screen.getByText('Switch state'))
    expect(screen.getByText("It's rolling!")).toBeInTheDocument()
    userEvent.click(screen.getByText('Switch state'))
    expect(screen.getByText("It's on!")).toBeInTheDocument()
  })

})
</code></pre>
<p>See that we import an additional utility called <code>userEvent</code>. This is an object that contains many methods we can use to simulate user fired events, like clicks, hovers, writting in an input, and so on.</p>
<ul>
<li><p>We first check that the default string is rendered: <code>expect(screen.getByText("It's on!")).toBeInTheDocument()</code></p>
</li>
<li><p>Then we simulate a click and check that the string changes in the screen:</p>
</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText('Switch state'))
expect(screen.getByText("It's rolling!")).toBeInTheDocument()
</code></pre>
<ul>
<li>And last we simulate another click and check that the string reverses back to default:</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText('Switch state'))
expect(screen.getByText("It's on!")).toBeInTheDocument()
</code></pre>
<p>To finish, we're going to write another test to verify that the text input and its toggle work correctly.</p>
<pre><code class="lang-plaintext">import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import About from './About'

describe('About', () =&gt; {

  ...

  test('Input works correctly', async () =&gt; {
    render( &lt;About/&gt; )

    userEvent.type(screen.getByTestId("testInput"), "Testing the test")
    userEvent.click(screen.getByText("Print input"))

    expect(screen.getByText("Testing the test")).toBeInTheDocument()

    userEvent.click(screen.getByText("Print input"))
    expect(screen.queryByText("Testing the test")).not.toBeInTheDocument()
  })


})
</code></pre>
<ul>
<li><p>Again we use the <code>userEvent</code> to simulate text being writen into our input element: <code>userEvent.type(screen.getByTestId("testInput"), "Testing the test")</code></p>
</li>
<li><p>Then we simulate a click on the toggle button, and check for the input text to be in the document:</p>
</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText("Print input"))
expect(screen.getByText("Testing the test")).toBeInTheDocument()
</code></pre>
<ul>
<li>And we close by simulating another click and checking that the test is no longer present:</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText("Print input"))
expect(screen.getByText("Testing the test")).toBeInTheDocument()
</code></pre>
<p>You can see how nice the utilities provided by Testing libraries are, and how easy it is to combine them with Jest. 🤓</p>
<p>We can run this specific test file by running <code>npm test -- About.test.jsx</code> and this is the result we get:</p>
<pre><code class="lang-plaintext">// console
PASS  src/components/About.test.jsx
  About
    ✓ About renders correctly (34 ms)
    ✓ Switch state works correctly (66 ms)
    ✓ Input works correctly (67 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        0.997 s, estimated 1 s
Ran all test suites matching /About.test.jsx/i.
</code></pre>
<p>The last Jest feature I'd like to show you is <strong>test coverage</strong>. You can obtain a coverage report by running <code>npm test -- --coverage</code>.</p>
<p>This will run your tests normally and at the end of the results report you should see something like this:</p>
<pre><code class="lang-plaintext">// console
...

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |      75 |      100 |   85.71 |      70 |                   
 src            |       0 |      100 |       0 |       0 |                   
  App.jsx       |       0 |      100 |       0 |       0 | 7                 
  App.t.js      |       0 |        0 |       0 |       0 |                   
  index.js      |       0 |      100 |     100 |       0 | 5-6               
 src/components |     100 |      100 |     100 |     100 |                   
  About.jsx     |     100 |      100 |     100 |     100 |                   
----------------|---------|----------|---------|---------|-------------------
</code></pre>
<p>In the report we can see that our <code>About.jsx</code> component is completely covered, but our <code>App.jsx</code> and <code>index.js</code> files are not being tested.</p>
<p>This feature is very handy when working on big projects and you want to quickly know if most of your code is being tested correctly.</p>
<h1 id="heading-how-to-test-a-front-end-react-app-with-cypress">How to Test a Front-end React App with Cypress</h1>
<p>We've talked a lot about Jest, so now let's take a look at how we can test our app using Cypress.</p>
<p>We'll start off by installing Cypress by running <code>npm i -D cypress</code>.</p>
<p>This should add this to our <code>package.json</code>:</p>
<pre><code class="lang-plaintext">"devDependencies": {
    "cypress": "^9.5.4"
}
</code></pre>
<p>Then we'll run <code>npx cypress open</code>. This will open the Cypress browser, and create a <code>cypress</code> directory within our project. Within this directory you'll find examples, documentation, and config options.</p>
<p>You'llo also find an "integration" folder, in which we have to put our tests. So let's create our <code>About.test.js</code> file in that folder and replicate the same test examples we've seen with Jest:</p>
<pre><code class="lang-plaintext">// About.test.js
describe('AboutPage', () =&gt; {
    it('Renders correctly', () =&gt; {
        cy.visit('http://localhost:3000/about')
        cy.contains("I'm the about page!")
    })

    it('switch btn toggles text', () =&gt; {
        cy.contains("It's on!")
        cy.get('.switchBtn').click()
        cy.contains("It's rolling!")
        cy.get('.switchBtn').click()
        cy.contains("It's on!")
    })

    it('Input works correctly', () =&gt; {
        cy.get(".testInput").type("Testing the test")
        cy.get('.printInputBtn').click()
        cy.contains("Testing the test")

        cy.get('.printInputBtn').click()
        cy.contains("Testing the test").should('not.exist')
    })
})
</code></pre>
<ul>
<li><p>The <code>describe</code> function works the same as in jest.</p>
</li>
<li><p><code>it()</code> is the same as the <code>test()</code> function we've previously seen.</p>
</li>
<li><p>In the first test we tell the browser to visit our app's URL and check that the corresponding text is rendered:</p>
</li>
</ul>
<pre><code class="lang-plaintext">cy.visit('http://localhost:3000/about')
cy.contains("I'm the about page!")
</code></pre>
<ul>
<li>Then we check that the default toggle text is rendered, simulate a click and check that it changes accordingly:</li>
</ul>
<pre><code class="lang-plaintext">cy.contains("It's on!")
cy.get('.switchBtn').click()
cy.contains("It's rolling!")
cy.get('.switchBtn').click()
cy.contains("It's on!")
</code></pre>
<ul>
<li>And to end we simulate a text input, simulate a click, and check that the input text is rendered:</li>
</ul>
<pre><code class="lang-plaintext">cy.get(".testInput").type("Testing the test")
cy.get('.printInputBtn').click()
cy.contains("Testing the test")

cy.get('.printInputBtn').click()
cy.contains("Testing the test").should('not.exist')
</code></pre>
<p>The syntaxt is slightly different than Jest, but the idea and structure are pretty much the same.🤙</p>
<p>Now if we run <code>npx cypress open</code> again, a window should open with this content:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/2022-04-23_22-30.png" alt="2022-04-23_22-30" width="600" height="400" loading="lazy"></p>
<p>We can click on "Run integration spec" and our test will run automatically in the mock browser. After the tests have run, on the left panel we'll see the results:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/2022-04-23_22-31.png" alt="2022-04-23_22-31" width="600" height="400" loading="lazy"></p>
<p>We can open those results to see each step the test executed. If we hover over each step, we'll see it executed in the browser in real time. A real sweet feature of Cypress.👌👌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/2022-04-23_22-34.png" alt="2022-04-23_22-34" width="600" height="400" loading="lazy"></p>
<p>As you can see, it's very easy to set up tests with Cypress. And if you're already familiar with Jest, you can quickly pick it up as the syntax is not that different.</p>
<p>If you're wondering if it makes sense to use both Jest and Cypress as test runners in the same project, <a target="_blank" href="https://stackoverflow.com/questions/66217682/should-i-use-both-cypress-and-jest-together">I think this stack-overflow answe</a>r sums it up quite nicely.</p>
<h1 id="heading-how-to-test-a-back-end-node-app">How to Test a Back-end Node App</h1>
<p>Now that we have a basic understanding of the ways we can tests a front-end app, let's cross the river and see how we can use similar tools to test a back end app.</p>
<p>For this we'll use a simple Node and Express API with just 3 endpoints.</p>
<p>Create a directory and run <code>npm init -y</code> to create a Node app. Run <code>npm i express</code> to install Express, and then run <code>npm i -D jest supertest</code> to install both Jest and Supertest as development dependencies.</p>
<p>Inside your <code>package.json</code>, add <code>"scripts": { "test": "jest" }</code>. Your entire <code>package.json</code> should look like this:</p>
<pre><code class="lang-plaintext">{
  "dependencies": {
    "express": "^4.17.3"
  },
  "devDependencies": {
    "jest": "^27.5.1",
    "supertest": "^6.2.2"
  },
    "scripts": {
    "test": "jest"
  }
}
</code></pre>
<p>Then create an <code>app.js</code> file and put this code in it:</p>
<pre><code class="lang-plaintext">// app.js
/* Import and initialize express */
const express = require('express')
const app = express()
const server = require('http').Server(app)
/* Global middlewares */
app.use(express.json())

/* Endpoint 1 */
app.get('/', async (req, res) =&gt; {

    try {
        res.status(200).json({ greeting: "Hello there!" })
    } catch (err) {
        res.status(500).send(err)
    }
})

/* Endpoint 2 */
app.get('/isPalindrome', async (req, res) =&gt; {

    try {
        const string = req.body.string
        let result = true        
        let left = 0
        let right = string.length-1

        while (left &lt; right &amp;&amp; result) {
            if (string[left] === string[right]) {
                left += 1
                right -= 1
            }
            else result = false
        }

        res.status(200).json({ result: result })

    } catch (err) {
        res.status(500).send(err)
    }
})

/* Endpoint 3 */
app.get('/twoSum', async (req, res) =&gt; {

    try {
        const nums = JSON.parse(req.body.nums)
        const target = JSON.parse(req.body.target)

        let result = false

        for (let i = 0; i &lt; nums.length; i++) {
            const neededNum = target - nums[i]
            if (nums.indexOf(neededNum) !== -1 &amp;&amp; nums.indexOf(neededNum) !== i) result = [nums[i], nums[nums.indexOf(neededNum)]]
        }

        res.status(200).json({ result: result })

    } catch (err) {
        res.status(500).send(err)
    }
})

/* Export server object */
module.exports = server

/* Initialize server */
server.listen(3001, () =&gt; console.log('Server is listening.') )
server.on('error', error =&gt; console.error(error) )
</code></pre>
<p>As you can see, endpoint 1 just returns a greeting message. Endpoint 2 and 3 are adaptations of the functions we've seen in our vanilla JS examples. They now receive the parameters within the request and the return values go in the response. 😉</p>
<p>Now the testing! Create an <code>app.test.js</code> file and put this code within it:</p>
<pre><code class="lang-plaintext">// app.test.js
const supertest = require('supertest') // Import supertest
const server = require("./app") // Import the server object
const requestWithSupertest = supertest(server) // We will use this function to mock HTTP requests

afterEach(done =&gt; { // afterEach function is provided by Jest and executes once all tests are finished
    server.close() // We close the server connection once all tests have finished
    done()
})

test('GET "/" returns greeting', async () =&gt; {
    const res = await requestWithSupertest.get('/')
    expect(res.status).toEqual(200)
    expect(res.type).toEqual(expect.stringContaining('json'))
    expect(res.body).toEqual({ greeting: "Hello there!" })
})

describe("/isPalindrome", () =&gt; {
    test('GET "/isPalindrome" neuquen returns true', async () =&gt; {
        const res = await requestWithSupertest.get('/isPalindrome').set('Content-type', 'application/json').send({ "string":"neuquen" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: true })
    })

    test('GET "/isPalindrome" bariloche returns true', async () =&gt; {
        const res = await requestWithSupertest.get('/isPalindrome').set('Content-type', 'application/json').send({ "string":"bariloche" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: false })
    })
})

describe("/twoSum", () =&gt; {
    test('GET "/twoSum" [2,7,11,15] and 9 returns [7, 2]', async () =&gt; {
        const res = await requestWithSupertest.get('/twoSum').set('Content-type', 'application/json').send({ "nums":"[2,7,11,15]", "target": "9" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: [7, 2] })
    })

    test('GET "/twoSum" [3,2,4] and 6 returns [4, 2]', async () =&gt; {
        const res = await requestWithSupertest.get('/twoSum').set('Content-type', 'application/json').send({ "nums":"[3,2,4]", "target": "6" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: [4, 2] })
    })

    test('GET "/twoSum" [3,2,4] and 10 returns false', async () =&gt; {
        const res = await requestWithSupertest.get('/twoSum').set('Content-type', 'application/json').send({ "nums":"[3,2,4]", "target": "10" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: false })
    })
})
</code></pre>
<p>Let's analyze what we're doing:</p>
<ul>
<li><p>We mock the request with <code>requestWithSupertest.get('/')</code></p>
</li>
<li><p>Then we "break" the <code>res</code> object in pieces and assert each part of it:</p>
<ul>
<li><p>Check the response status: <code>expect(res.status).toEqual(200)</code></p>
</li>
<li><p>Check the response format: <code>expect(res.type).toEqual(expect.stringContaining('json'))</code></p>
</li>
<li><p>Check the response body content: <code>expect(res.body).toEqual({ greeting: "Hello there!" })</code></p>
</li>
</ul>
</li>
</ul>
<p>The other tests are really similar, except we're sending data in the mock requests bodies, like this:</p>
<pre><code class="lang-plaintext">const res = await requestWithSupertest.get('/isPalindrome').set('Content-type', 'application/json').send({ "string":"bariloche" })
</code></pre>
<p>As you can see, testing in this way is really simple once you're familiar with Jest. We just need a little help by Supertest to mock the HTTP request and the rest is just asserting the response. 👏👏</p>
<p>We can run our tests with <code>npm test</code> and we should get the following response:</p>
<pre><code class="lang-plaintext">// console
 PASS  ./app.test.js
  ✓ GET "/" returns greeting (46 ms)
  /isPalindrome
    ✓ GET "/isPalindrome" neuquen returns true (18 ms)
    ✓ GET "/isPalindrome" bariloche returns true (3 ms)
  /twoSum
    ✓ GET "/twoSum" [2,7,11,15] and 9 returns [7, 2] (4 ms)
    ✓ GET "/twoSum" [3,2,4] and 6 returns [4, 2] (3 ms)
    ✓ GET "/twoSum" [3,2,4] and 10 returns false (2 ms)

Test Suites: 1 passed, 1 total
Tests:       6 passed, 6 total
Snapshots:   0 total
Time:        0.552 s, estimated 1 s
Ran all test suites.
</code></pre>
<h1 id="heading-wrap-up">Wrap up</h1>
<p>And that's it! We've covered the basics of four very popular tools that will allow you to test both the front-end and back-end of your JS apps.</p>
<p>Of course there's much more to all the tools we've seen and many features we haven't covered. But the idea was to give you an introduction so you can take your first steps in the testing world.</p>
<p>As always, I hope you enjoyed the article and learned something new. If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/germancocca/">linkedin</a> or <a target="_blank" href="https://twitter.com/CoccaGerman">twitter</a>.</p>
<p>Cheers and see you in the next one! =D</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/goodbye-bye--1-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Risk-Based Testing: A Balanced & Effective Approach To Testing ]]>
                </title>
                <description>
                    <![CDATA[ By Rashmi Sharma Stakeholders are always pushing searching for faster solutions. Project managers are rushing products to the delivery table. And there is isn't necessarily anything wrong with doing it this way. But it can be challenging for QA testi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/risk-based-testing-a-balanced-effective-approach-to-testing/</link>
                <guid isPermaLink="false">66d460c9c7632f8bfbf1e493</guid>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 25 Feb 2021 15:58:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/02/photo-1574790398664-0cb03682ed1c--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rashmi Sharma</p>
<p>Stakeholders are always pushing searching for faster solutions. Project managers are rushing products to the delivery table. And there is isn't necessarily anything wrong with doing it this way.</p>
<p>But it can be challenging for QA testing teams who have to embrace this super quick timetable, and then convince the developer team to get onboard.</p>
<p>Software teams know how badly test management teams want to reach deadlines when they are coping with constant shifts and changes.</p>
<p>In this scenario, all blame falls on the test team, who might quickly become a convenient target when production bugs are shipped. And any delays regarding specifications and implementation in the upstream software development lifecycle (SDLC) phase will make matters worse. </p>
<p>Beyond that, the demands of the stakeholders who want the product available ASAP add fuel to the fire. All of this puts the testing team under immense pressure.</p>
<p>A QA team must have a rational and empirical response to this challenge. The answer to this problem lies in <a target="_blank" href="https://www.kualitee.com/test-management/best-test-management-tools-must-used-2019/">risk-based testing (RBT)</a> which can help the testing team deliver on their deadlines. </p>
<p>Your test team can save a ton of effort with the RBT strategy, and it produces great savings while delivering the project on time.</p>
<h2 id="heading-what-is-risk-based-testing-rbt-basics">What is Risk-Based Testing? RBT Basics</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/dm.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In risk-based test management, you find the greatest market threats (that would have a detrimental effect on the enterprise as defined by the consumer) early in the development cycle and then you can counter them by taking preventive steps.</p>
<p>These market threats may include increased costs, consumer disappointment, poor user interface, and lost customers. And RBT can help you mitigate them by conducting testing in such a way that, even if a customer gets an error, they can go on using the application (and the organization isn't greatly affected).</p>
<p>RBT involves testing that's performed on the basis of product risks. It's useful in helping you discover how likely a specific feature or capability is to fail in final output/production. It'll also help you determine this failure's effect on the company in terms of cost and other damages, well ahead of time. And it does this by using a prioritization strategy for test cases.</p>
<p>So Risk-Based evaluation works by prioritizing the testing of a product or software's functionality, components, and features. This prioritization is based on the risk of the possibility of failure in the development of the feature or functionality and its effect on clients.</p>
<h2 id="heading-how-to-assess-risk-with-rbt">How to Assess Risk with RBT</h2>
<p>RBT includes risk management and test prioritization depending on the risk factor of each test. The risk factor is the result of the likelihood and possible effect of future risk. </p>
<p>But how are we able to come up with those values? To allocate a risk factor to a specific risk, here are three requirements to consider.</p>
<h3 id="heading-code-complexity">Code Complexity</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/complexity.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Cyclomatic Complexity</em></p>
<p>The more ambiguous code is, the more likely flaws will be discovered. Simply put, it is more likely that more complicated code contains glitches. The reverse is also true: the cleaner and simpler the code, the less likely it is to contain errors.</p>
<p>The problem then is how you should calculate code complexity. One measure is <a target="_blank" href="https://www.tutorialspoint.com/software_testing_dictionary/cyclomatic_complexity.htm">cyclomatic complexity</a> which refers to the number of potential paths. The minimal number of test cases you require to thoroughly test a feature is determined by that number. In fact, code with high cyclomatic complexity, which may expand the number of errors, can be more difficult to read.</p>
<h3 id="heading-churn-or-number-of-modifications-to-the-code">Churn or number of modifications to the code</h3>
<p>Churn here implies the number of modifications that a specified file or module experiences. An application area that developers alter more frequently is more likely to have bugs than one which they hardly ever touch.</p>
<p>A great example of this is an application for e-commerce that has been in development for many years. The software team is likely to make frequent adjustments to the offers, introduce new features, and try experiments to boost purchases. The affected sections of the code shift regularly and are thus more likely to produce errors.</p>
<p>When <a target="_blank" href="https://dzone.com/articles/code-churn-a-magical-metric-for-software-quality">churn</a> is significant, extensive testing should be proposed for risk-based planning: more UI tests, more unit tests, more integration tests, and so on.</p>
<h3 id="heading-criticality">Criticality</h3>
<p>Criticality involves the calculation of a <a target="_blank" href="https://techbeacon.com/app-dev-testing/how-slash-high-cost-defects">software defect's</a> influence on your application. Criticality is not spread equally through a codebase. Many systems are expected to have a high-critical code core on which the remainder of the application relies. </p>
<p>If the code does not perform properly, several parts of the software could be compromised and it would probably create defects. If it applies to safety-related software, a critical flaw may cause data loss, sensitive data disclosure, and maybe even endanger lives.</p>
<p>When measuring the effect portion of the risk factor, criticality may be useful.</p>
<p>If a bug arises in the application's most important environment, the effects could be much more extreme than if it existed in some area that included utility code only.</p>
<p>We rely on our algorithms in our test management frameworks to classify site components. If web components can not be detected by the algorithm and related core code, the UI checks if our customers will make mistakes or fail, creating frustration, reworks, service calls, and a lack of faith in our solution. </p>
<p>Worse still, if false positives are generated by our application, it will interrupt the CI/CD process and impede the implementation of a legitimate application.</p>
<h2 id="heading-smart-testing-is-the-solution">Smart Testing Is the Solution</h2>
<p>Software development companies need a better strategy when it comes to software testing than "just test everything." Not all code is equal, not all threats are credible, and not all bugs trigger equal harm. </p>
<p>In order to make informed decisions about how to distribute capital and test them more effectively, tech companies must take these RBT considerations into account.</p>
<p>If you want to remain on top of your Risk-Based Software Testing, you can check out <a target="_blank" href="https://www.kualitee.com/">Kualitee</a> – we're a software testing and information security company.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Google Does Code Reviews – Quality Assurance Tips from Google's Documentation ]]>
                </title>
                <description>
                    <![CDATA[ A code review, sometimes called code Quality Assurance, is the practice of having other people check your code after you write it.  Code reviews bring many benefits to the process of writing and delivering software: Ensures consistency through your ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-google-taught-me-about-code-reviews/</link>
                <guid isPermaLink="false">66bc55edda80a491ea5a5f5f</guid>
                
                    <category>
                        <![CDATA[ code review ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google ]]>
                    </category>
                
                    <category>
                        <![CDATA[ QA ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kealan Parr ]]>
                </dc:creator>
                <pubDate>Thu, 14 Jan 2021 18:09:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/Google.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A code review, sometimes called code Quality Assurance, is the practice of having other people check your code after you write it. </p>
<p>Code reviews bring many benefits to the process of writing and delivering software:</p>
<ul>
<li>Ensures consistency through your codebase.</li>
<li>Teaches all members of the review (helps knowledge transfer).</li>
<li>Builds contextual awareness regarding what might affect other parts of the team</li>
<li>Helps avoid breaking builds</li>
<li>Casts fresh eyes over a code change to search for optimisations and simplifications in the change.</li>
<li>Promotes quality and helps make sure no one forgot or missed anything.</li>
</ul>
<p>Google has 1,918 repositories on <a target="_blank" href="https://github.com/google">their GitHub</a> across multiple languages, and even more that aren't open source.</p>
<p>One of their codebases is shared by over 25,000 Googlers, and typically has <a target="_blank" href="https://cacm.acm.org/magazines/2016/7/204032-why-google-stores-billions-of-lines-of-code-in-a-single-repository/fulltext">40,000 commits</a> daily (16,000 human changes, and 24,000 by automated systems). Each day it has to serve around 800,000 queries per second during peak times.</p>
<p>Google has published their engineering practices, so let's see how they review code at their scale, with so many commits a day.</p>
<p>Google refers to changes in their codebases as <strong>CLs</strong> standing for change lists. It's just a unit of work / piece of code going through review. </p>
<h1 id="heading-how-to-prepare-for-code-reviews">How to Prepare for Code Reviews</h1>
<p>Firstly, before you even think about the code review process, try and focus on <strong>who</strong> will do the review. Try to pick a subject matter expert. Pick someone who is familiar with this codebase or area of the codebase. </p>
<p>Sometimes this may even mean having different people review different parts of the code. But less <a target="_blank" href="https://sback.it/publications/icse2018seip.pdf">than 25% of code review's at Google have more than one reviewer.</a></p>
<p>Getting someone to respond in a timely manner is also important. To avoid bottle necks and overloading individuals, just CC reviewers onto the change to review it at their convenience if they want to.</p>
<h1 id="heading-how-to-run-fast-code-reviews">How to Run Fast Code Reviews</h1>
<p>Code reviews should be completed quickly. The <strong>maximum</strong> length of time for a review should be one business day.</p>
<p>Why the urgency? I've personally had QA's sometimes take weeks or longer.</p>
<ul>
<li><strong>It becomes a blocker.</strong> Although the author of the code moves onto new work, new changes start to form a back log, and the delays can build up to weeks or months.</li>
<li><strong>Developers feel frustrated.</strong> If the reviewer asks for major changes but only responds every 3 days, it is frustrating for the developer working on that change. But with quick responses, whenever you require explanation of exactly what you need to do, the frustration fades away.</li>
<li><strong>Code quality can degrade.</strong> If your reviews are always slow, developers are less likely to do code clean ups, refactoring work or general code improvement ("If my reviewer won't reply for 4 days what's even the point?"), and the code quality submitted in the reviews is more likely to go down.</li>
</ul>
<p>The main reason code reviews can be fast is because they're small. Rather than sending a 1,000 line CL, they're separated into multiple CL's – pushing 10 smaller changes of 100 lines for example.</p>
<p>Google also has emergencies where code changes have to be made quickly to resolve major problems in production. In these cases, code quality is relaxed. This review should immediately become the reviewers first priority. There are some examples of emergencies Google has faced <a target="_blank" href="https://www.freecodecamp.org/news/what-is-a-software-post-mortem/">here</a> if you're curious.</p>
<h2 id="heading-googles-code-review-standards">Google's Code Review Standards</h2>
<p>The key rule Google emphasizes is:</p>
<p><strong>Reviewers should generally approve a change once it definitely improves the overall code health, even if it isn't perfect.</strong></p>
<p>The key point Google seem to be making is that perfect code doesn't exist. If it makes it <strong>better</strong>, that is enough. </p>
<p>It's definitely a balancing act between something being better, and <strong>how</strong> much better it could be. If you could add more feedback to make significant improvements, there may need to be more work done on the code.</p>
<h2 id="heading-what-googlers-look-for-in-code-reviews">What Googlers Look for in Code Reviews</h2>
<p>When doing code reviews, Google focuses on these elements according to their <a target="_blank" href="https://google.github.io/eng-practices/review/reviewer/looking-for.html">engineering practices documentation</a>:</p>
<blockquote>
<p><strong>Design</strong>: Is the code well-designed and appropriate for your system? Does this change belong in your codebase, or in a library? Does it integrate well with the rest of your system?  </p>
<p><strong>Functionality</strong>: Does the code behave as the author likely intended? Is the way the code behaves good for its users? Mostly, we expect developers to test CLs well-enough that they work correctly by the time they get to code review.   </p>
<p><strong>Complexity</strong>: Could the code be made simpler? Would another developer be able to easily understand and use this code when they come across it in the future? Is it over-engineered for its current use case?  </p>
<p><strong>Tests</strong>: Does the code have correct and well-designed automated tests? Will the tests actually fail when the code is broken? Will they start producing false positives? Does each test make simple and useful assertions?  </p>
<p><strong>Naming</strong>: Did the developer choose clear names for variables, classes, methods, etc.?  </p>
<p><strong>Comments</strong>: Are the comments clear and useful? Ensure where sensible comments explain <strong>why</strong> something is being done, rather than how.  </p>
<p><strong>Style &amp; Consistency</strong>: Does the code follow our <a target="_blank" href="http://google.github.io/styleguide/">style guides</a>?  </p>
<p><strong>Documentation</strong>: Did the developer also update relevant documentation?</p>
</blockquote>
<p>Google has style guides for multiple languages like <a target="_blank" href="https://google.github.io/styleguide/cppguide.html">C++</a>, <a target="_blank" href="https://google.github.io/swift/">Swift</a>, <a target="_blank" href="https://google.github.io/styleguide/htmlcssguide.html">HTML/CSS</a>, <a target="_blank" href="https://google.github.io/styleguide/lispguide.xml">Lisp</a>, <a target="_blank" href="https://google.github.io/styleguide/jsguide.html">JavaScript</a> and <a target="_blank" href="https://google.github.io/styleguide/">more.</a></p>
<p>Having a document that everyone can refer to helps standardise the code. It also helps clarify what the expectations are in the review process.</p>
<h2 id="heading-how-googlers-review-code">How Googlers Review Code</h2>
<p>There is a three-stage process for code review in Google's engineering practices. Here's a list of things you'd need to cover if you were to review:</p>
<ol>
<li>Get a high level overview of the change</li>
<li>Examine the main parts of the change</li>
<li>Look through the rest of the code, in a sensible order</li>
</ol>
<p>Let's go over each step in more detail.</p>
<h2 id="heading-1-get-a-high-level-overview-of-the-code-change">1. Get a High Level Overview of the Code Change</h2>
<p>Look at the code change's description/summary. Does it all make sense? For example, if someone is changing a codebase that is being deleted next week, push back on the change <em>courteously,</em> and explain why the change doesn't look needed anymore. </p>
<p>It's inefficient if people are spending time on work that isn't actually needed, so have a look at your development life cycle and see why this might be happening. The earlier you can catch these issues the better.</p>
<p>In order to get a high level overview of the code, you may want to briefly scan the code components to see how it all works together. </p>
<p>If you see a serious architectural problem or something majorly wrong, you should share your observations immediately at this stage. Even if you don't have time to review every single other element of the review. Reviewing the rest may well even end up being a waste of time if the architectural problems are severe enough. </p>
<p>Aside from this, there are 2 major reasons why you should send your review comments immediately: </p>
<ul>
<li>Googlers will often email a change, and then immediately start new work based on that change. If the change in review need serious adjustments, they may be building on something that needs to be significantly changed.</li>
<li>Big changes to the CL may take a while to finish. Developers all have deadlines and it's courteous to try and help them meet them by letting them start rework as soon as possible.</li>
</ul>
<h2 id="heading-2-examine-the-main-parts-of-the-code-change">2. Examine the Main Parts of the Code Change</h2>
<p>Once you have had an overview, review the "main" parts of the change.</p>
<p>Find the file or files that are central to the CL. Often, there is one file that has the largest number of changes, and it’s the major piece of the CL.</p>
<p>Spend most of your focus reviewing these pieces. This provides context to all the smaller pieces, and generally makes it faster to review. </p>
<p>If the CL is too large for you to get a good overview and understand the flow, it's a good sign the developer should be splitting up their CL into smaller changes.</p>
<h2 id="heading-3-look-through-the-rest-of-the-code-in-a-sensible-order">3. Look Through the Rest of the Code, in a Sensible Order</h2>
<p>Once you have a good overview of the change, it's time to drill down into the details and go file by file. </p>
<p>Each reviewer generally does this differently. Some go in the order that the version control presents to them and some pick a particular order. Choose what makes sense to you. It's important to just review <strong>everything</strong>, and miss nothing.</p>
<h3 id="heading-review-every-line-of-code">Review Every Line of Code</h3>
<p>Don't miss or skim important details. Sometimes there might be config files, or generated code you can scan briefly looking for irregularities. But your job here is to be very thorough and carefully scrutinise the code. </p>
<p>Make sure you think about bugs, race conditions, alternate approaches, conciseness, readability, and so on.</p>
<p>If you can't understand the code, it's highly likely other developers won't be able to either, and should ask the developer to clarify it.</p>
<h3 id="heading-understand-the-context">Understand the Context</h3>
<p>Often times the version control software will only show the changed lines. But it's important to read the lines before and after, or the whole file, to ensure you understand exactly what the change is doing.  </p>
<p>You may only see someone adding 2 more <code>if</code> blocks in a change. But if you look at the context you might see that the <code>if</code> <code>else</code> block now has 15 different <code>if</code>'s inside it. Then you can reject the code change and properly improve the code quality in this area, rather than making it worse.</p>
<p>Remember code degradation happens slowly, with every change that goes in. Our main aim is to ensure the quality trends consistently up, and we never go backwards.</p>
<h2 id="heading-how-googlers-write-code-feedback"><strong>How Googlers Write Code Feedback</strong></h2>
<p>Google has some specific sections covering how to do <a target="_blank" href="https://chromium.googlesource.com/chromium/src/+/master/docs/cr_respect.md">code reviews courteously, and respectfully</a>. This isn't in opposition to being clear and as helpful as you can to the developer. The golden rule here is to make comments about the <em>code</em> and not the developer. </p>
<h2 id="heading-what-to-do">What to Do:</h2>
<p>#### </p>
<blockquote>
<p><strong>Ask for the why:</strong> If it is unclear why the author is doing things a certain way, feel free to ask why they made a particular change. Not knowing is OK, and asking “Why” leaves a written record that will help answer this question in the future. (And sometimes, “I'm curious, why did you decide to do it that way?” can help the author to rethink their decision.)  </p>
<p><strong>Find an end:</strong> If you like things neat, it’s tempting to go over a code review over and over until it’s perfect, dragging it out for longer than necessary. It’s soul-deadening for the recipient, though. Keep in mind that “LGTM” does not mean “I vouch my immortal soul this will never fail”, but “looks good to me”. If it looks good, move on. (That doesn’t mean you shouldn’t be thorough. It’s a judgment call.) And if there are bigger refactorings to be done, move them to a new CL. (<a target="_blank" href="https://chromium.googlesource.com/chromium/src/+/HEAD/docs/cr_respect.md">Source</a>)</p>
</blockquote>
<h2 id="heading-what-not-to-do">What Not to Do</h2>
<blockquote>
<p><strong>Don't use extreme or very negative language:</strong> Please don't say things like “no sane person would ever do this” or “this algorithm is terrible”, whether it’s about the change you're reviewing or about the surrounding code. While it might intimidate the reviewee into doing what you want, it’s not helpful in the long run - they will feel incapable, and there is not much info in there to help them improve. “This is a good start, but it could use some work” or “This needs some cleanup” are nicer ways of saying it. Discuss the code, not the person.  </p>
<p><strong>Don't bikeshed:</strong> Always ask yourself if this decision <em>really</em> matters in the long run, or if you're enforcing a subjective preference. It feels good to be right, but only one of the two participants can win that game. If it’s not important, agree to disagree, and move on. (<a target="_blank" href="https://chromium.googlesource.com/chromium/src/+/HEAD/docs/cr_respect.md">Source</a>)</p>
</blockquote>
<p>Remember code reviews can sometimes trend towards finding issues or discussions with code and not praise.</p>
<p>If your reviewer has addressed your comments, or they have done some optimisation or smart code you like, thank them. Say you like the approach / how they have solved an issue. </p>
<p>Conversely, thank the reviewer if they thoroughly explain what they want and promptly answer your questions.</p>
<p>I have had some reviews where reviewers have put huge comments explaining something I misunderstood and I can still remember who it was and what they said.</p>
<h2 id="heading-how-to-handle-pushback-in-code-reviews">How to Handle Pushback in Code Reviews</h2>
<p>Sometimes the developer who is receiving the review might disagree with the changes that you're proposing. Here's how to handle that.</p>
<h3 id="heading-consider-that-they-might-be-right">Consider That They Might Be Right</h3>
<p>Sometimes the developer is closer to the code and how it works, and they may be right. If they are, move on from that discussion point and leave that code as it is.</p>
<p>But if they're not, or they've misunderstood something, you should insist on the change. Respond to what the developer initially challenged you on, and explain your reasoning courteously. </p>
<p>Code quality improvements tend to happen in small incremental steps, and review is one way it happens. Insist on the code improvement, even if it means extra work for the developer.</p>
<h3 id="heading-try-to-avoid-ill-fix-this-later">Try to Avoid "I'll fix this later..."</h3>
<p>One of the most common issues in reviews is not that people disagree whether the code change is necessary, but rather that they want to do it under a different ticket or do it later. So if you pass this review, they assure you that they will follow up later and fix the issues.</p>
<p>Generally speaking, <em>following up later</em> rarely happens. This doesn't mean there's something wrong with the developer or their work ethic. But it's easy to forget, have priorities change, or even just get lost in their queue of work. </p>
<p>Insist that the work gets done now. There is no real fantastic gain to merging changes in the codebase you have to immediately fix. You are just adding technical debt that <em>might</em> be followed up on later, or might be forgotten<em>.</em> Fixing lots of tickets later is an easy way for quality to drop.</p>
<p>The only exception to this is <a target="_blank" href="https://google.github.io/eng-practices/review/emergencies.html">emergencies</a>, which involve the highest priority bugs Google deals with where there is something seriously wrong. This could be services going down, or errors crashing people's pages in production.</p>
<p>There is naturally an eagerness to merge changes ASAP, and the review might accept slightly lower quality, with a follow up fix immediately being written. The main point is that the first change removes the emergency, and the second change fixes it <em>properly.</em></p>
<h1 id="heading-conclusion"><strong>Conclusion</strong></h1>
<p>I hope this has explained some helpful concepts Google makes use of in their code review process. I wrote this to better cement it into my own mind, and was curious about how other companies handle the QA process. </p>
<p>I found that there are quite a few points that I can take away and apply to the reviews I conduct.</p>
<p>The document I referred to throughout this article can be found <a target="_blank" href="https://google.github.io/eng-practices/review/reviewer/">here</a>.</p>
<p>I share my writing on <a target="_blank" href="https://twitter.com/kealanparr">Twitter</a> if you enjoyed this article and want to see more.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test and Play with Web APIs the Easy Way with Postman ]]>
                </title>
                <description>
                    <![CDATA[ In a world where static websites and apps increasingly depend on separately maintained APIs, it can be hard to figure out how they work by just playing around in the browser.  So how can we use Postman to both test our existing APIs and understand ho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-test-and-play-with-web-apis-the-easy-way-with-postman/</link>
                <guid isPermaLink="false">66b8e36e47e3b55b9fb6ee45</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer Tools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ QA ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tools ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Tue, 30 Jun 2020 16:34:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/06/postman.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In a world where static websites and apps increasingly depend on separately maintained APIs, it can be hard to figure out how they work by just playing around in the browser. </p>
<p>So how can we use Postman to both test our existing APIs and understand how they work?</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-postman">What is Postman?</a></li>
<li><a class="post-section-overview" href="#heading-what-are-we-going-to-build-learn">What are we going to build / learn?</a></li>
<li><a class="post-section-overview" href="#heading-part-0-getting-set-up-with-postman">Part 0: Getting set up with Postman</a></li>
<li><a class="post-section-overview" href="#heading-part-1-an-introduction-to-postman">Part 1: An introduction to Postman</a></li>
<li><a class="post-section-overview" href="#heading-part-2-creating-a-new-postman-request-to-get-info-about-squirtle">Part 2: Creating a new Postman request to GET info about Squirtle</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/a02335e1-4f9a-453d-8916-db6b8419cf99/part-3-creating-a-collection-of-requests-in-postman-for-the-pok-api">Part 3: Creating a collection of requests in Postman for the PokéAPI</a></li>
<li><a class="post-section-overview" href="#heading-part-4-making-post-requests-with-postman-to-translate-sentences-to-sound-like-yoda">Part 4: Making POST requests with Postman to translate sentences to sound like Yoda</a></li>
<li><a class="post-section-overview" href="#heading-part-5-authenticating-requests-to-the-lord-of-the-rings-api-with-an-api-key">Part 5: Authenticating requests to the Lord of the Rings API with an API Key</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/KFuaybrXCdw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-is-postman">What is Postman?</h2>
<p><a target="_blank" href="https://www.postman.com/">Postman</a> is a tool teams can use to reliably test APIs using easy to use configurations. It comes stocked with features you would expect when dealing with APIs, including authentication, setting headers, customizing the payload, and a bunch more that help reduce the friction of using an API.</p>
<p>And it’s not just for testing. The beauty is that this can be used for many aspects of working with APIs for many different members of the team. Maybe a Project Manager wants to verify that things work or might find it easier to make a change straight with the API, or a QA Engineer needs to make sure everything still works, or a developer wants to actively make changes while working on the API itself.</p>
<p>The best part about it – Postman provides collaboration features. The free tier includes exporting and importing collections of saved API requests as well as creating shared links. If you're part of a team, they have paid tiers that allow you to sync up your collections to make sure everyone has the most recent and up to date collection.</p>
<h2 id="heading-what-are-we-going-to-build-learn">What are we going to build / learn?</h2>
<p>We’re going to walk through two different example APIs to cover the concepts of Postman.</p>
<p>First, we’ll walk through some simple HTTP requests with a <a target="_blank" href="https://pokeapi.co/">public API for Pokémon</a>.</p>
<p>We’ll then use the Yoda Translator API for one part to demonstrate how to make specific HTTP requests.</p>
<p>Once we understand how the basics work, we’ll use the <a target="_blank" href="https://the-one-api.herokuapp.com/">Lord of the Rings API</a> to learn how authentication works with APIs. For this, you’ll need to register for a free account for an API key.</p>
<h2 id="heading-part-0-getting-set-up-with-postman">Part 0: Getting set up with Postman</h2>
<p>Before we get started, you’ll need <a target="_blank" href="https://www.postman.com/downloads/">Postman</a> in order to follow along with this walkthrough. The good news, is Postman is available for free on Mac, Windows, and Linux, so you should be able to find a version that works for you.</p>
<p>Get Postman: <a target="_blank" href="https://www.postman.com/downloads/">https://www.postman.com/downloads/</a></p>
<p>Once downloaded, go through the standard installation instructions, open it up, and we should be ready to go!</p>
<h2 id="heading-part-1-an-introduction-to-postman">Part 1: An introduction to Postman</h2>
<p>The first time you open up Postman you’ll immediately be shown a launchpad with a bunch of options to get started.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-launchpad.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It might seem a bit overwhelming, but let’s break down some of the key concepts that we’ll need to know.</p>
<h3 id="heading-requests">Requests</h3>
<p>A request is kind of what it sounds like, it’s a specific API request. This will be a single type of request, whether it’s a GET or POST to a specific endpoint. You’ll want to create new requests for each type of endpoint which will allow you to move between them when testing.</p>
<h3 id="heading-collections">Collections</h3>
<p>A collection is a group of requests. This is handy for organizing your requests into different groups. This could be as simple as two totally different APIs (ie. Twitter vs Slack) or it could be two different groups of APIs for a single API (ie. Twitter Tweets API vs Twitter Accounts API).</p>
<h3 id="heading-authorization">Authorization</h3>
<p>Authorization is how requests are authenticated with an API, whether by a person making a request or by a computer making that request on your behalf. This commonly comes in the form of an API key which can be a static value assigned to your account or dynamically generated with tools like <a target="_blank" href="https://oauth.net/">OAuth</a>.</p>
<h3 id="heading-environments">Environments</h3>
<p>Environments will allow you to configure your endpoints to use specific variables that make it easier to use the same endpoints between different environments. For instance, you might have the same <code>/profile</code> endpoint on both your production and development environments, but they have different domains. Environments lets you manage a single request with a variable domain.</p>
<h3 id="heading-workspaces">Workspaces</h3>
<p>We won’t go too far into workspaces in this post, but it allows you to manage and organize different sets of collections. Imagine if you want to use Postman for both work and a personal project, you might have a Work workspace as well as a Personal workspace.</p>
<p>For the purposes of this article, we’ll be covering Requests, Collections, and Authorization.</p>
<h2 id="heading-part-2-creating-a-new-postman-request-to-get-info-about-squirtle">Part 2: Creating a new Postman request to GET info about Squirtle</h2>
<p>Now that we have a better understanding of the different terminology, let’s actually create a request.</p>
<p>At the top left of the UI you should see a but orange button that says <strong>New</strong>. Go ahead and click that and then select <strong>Request</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-create-new-request.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Before we get into the request itself, it requests a few things.</p>
<p>This first thing requires is a name. We’re going to start off by requesting information about the Pokémon Squirtle, so let’s name this “Pokémon - Squirtle”.</p>
<p>It also requires a collection, so click <strong>Create Collection</strong> and let’s name the collection “My Favorite Pokémon”.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-configure-new-request.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click the orange checkmark button next to the collection name then hit <strong>Save</strong>.</p>
<p>At this point we’ll have a new request, so let’s build that request.</p>
<p>There are two things we’ll first need to fill out for our first request:</p>
<ul>
<li><strong>Request type:</strong> GET, POST, PUT, etc - we’ll use GET</li>
<li><strong>Request URL:</strong> The endpoint for your API request - for our request we’ll use <a target="_blank" href="https://pokeapi.co/api/v2/pokemon/squirtle/">https://pokeapi.co/api/v2/pokemon/squirtle/</a></li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-squirtle-pokemon-get.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And once you make sure those are correct, you can simply hit the blue <strong>Send</strong> button on the right and we’ve successfully made our first request!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-squirtle-pokemon-get-success.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We immediately get a few things we can see:</p>
<ul>
<li><strong>Body:</strong> at the bottom we should now see the response body of the API request. For our Squirtle API, we should have a JSON object with data like <code>abilities</code>, <code>base_experience</code>, and <code>forms</code>.</li>
<li><strong>Status:</strong> on the right, we should see the HTTP status code. “200 Ok” is a good sign and it means it was successful!</li>
<li><strong>Time:</strong> simply how long the request took to finish</li>
<li><strong>Size:</strong> the size in KB (in our example) of the response data</li>
</ul>
<p>You can also hover over Status, Time, and Size and get a more in depth look at each option.</p>
<p>So we made our first request!</p>
<p>Once thing to notice before we move on is that our request looks like it’s in a browser tab. If we’re done with that particular request, we can close the tab and click <strong>Save</strong> to make sure all of our changes are there for next time!</p>
<h2 id="heading-part-3-creating-a-collection-of-requests-in-postman-for-the-pokeapi">Part 3: Creating a collection of requests in Postman for the PokéAPI</h2>
<p>Now that we’ve created a request, let’s create a collection of them. Technically we already had to create a new collection for Part 2, but we’ll create a new one to learn how collections themselves work.</p>
<p>At the top left of the UI, click the orange <strong>New</strong> button again and select <strong>Collection</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-create-new-collection.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Similar to a request, it asks for a name so let’s call this “PokéAPI”. Optionally you can add a description, then click <strong>Create</strong> at the bottom.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-configure-new-collection.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>On the left, you’ll now see your collection. You can select and expand the folder since we’ll be working with it.</p>
<p>Before we add a request, the PokéAPI has different types of requests, so it makes sense to organize it a little more thoroughly. So let’s click the three dots next to the PokéAPI collection and select <strong>Add Folder</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-add-folder-to-collection.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Similar to the others, this asks for a name. Folders are kind of like collections inside of a collection, so you get similar options. Let’s name this one “Pokémon” and click the orange <strong>Save</strong> button like before.</p>
<p>Now let’s add our requests! First, click the three dots next to the Pokémon folder, similar to how we added a folder to the collection, but this time select <strong>Add Request</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-add-request-to-collection.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let’s name this request “Pokemon”. While it might be confusing that we have a Pokemon request inside of the Pokémon folder, Pokemon is just one of the endpoints of the Pokémon group.</p>
<p>Now, let’s use the same exact API that we used with our Squirtle request before:</p>
<ul>
<li><strong>Request Type:</strong> GET</li>
<li><strong>Request URL:</strong> <a target="_blank" href="https://pokeapi.co/api/v2/pokemon/squirtle/">https://pokeapi.co/api/v2/pokemon/squirtle/</a></li>
</ul>
<p>And similar to before, when we hit the blue <strong>Send</strong> button, we should see a successful request!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-successful-get-request-squirtle.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now let’s add another request. Follow the same process as before to create a new request under the PokéAPI Pokémon folder and let’s name this request “Abilities”.</p>
<p>If you scroll through the response from the first Squirtle endpoint, you see a lot of other API urls. At the top, we have <code>abilities</code> and we have two different ones — “torrent” and “rain-dish”.</p>
<p>Choose your favorite Squirtle ability and copy the <code>url</code> value into the new Abilities request we just created, I’m going to use <code>rain-dish</code>.</p>
<p>We can leave the Request Type as GET, hit the blue <strong>Send</strong> button, and we can again see a successful response!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-successful-request-squirtle-abilities.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here we get a lot of information about our Squirtle ability Rain Dish and some of the details come in different languages which is cool!</p>
<p>So now we have a new PokéAPI collection with a Pokémon folder representing the group of Pokémon API endpoints including Pokemon and abilities.</p>
<p>We’re going to stop Part 3 with those 2 requests, but feel free to continue on and add as many of the PokéAPI requests as you’d like!</p>
<h2 id="heading-part-4-making-post-requests-with-postman-to-translate-sentences-to-sound-like-yoda">Part 4: Making POST requests with Postman to translate sentences to sound like Yoda</h2>
<p>So far we’ve only made GET requests, but what if we wanted to make a POST request where we need to actually send some data?</p>
<p>For making a POST request, we’re going to use the Yoda Translator API from funtranslations.com. While this API only takes a single parameter, it’s still a good public endpoint we can use to understand the concept.</p>
<p>First, let’s create a new collection with a new request:</p>
<ul>
<li><strong>Collection:</strong> Fun Translations</li>
<li><strong>Request:</strong> Yoda</li>
</ul>
<p>This time, instead of a GET request, our request configuration will be:</p>
<ul>
<li><strong>Request Type:</strong> POST</li>
<li><strong>Request URL:</strong> <a target="_blank" href="https://api.funtranslations.com/translate/yoda">https://api.funtranslations.com/translate/yoda</a></li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-new-request-yoda-api.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now this time, if we hit the blue <strong>Send</strong> button, we’ll notice we don’t get a successful 200 response, we get a 400!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-yoda-api-bad-request.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We never actually set up any data to be posted to the API and it requires that data, so let’s add it.</p>
<p>Right below the <strong>Request URL</strong>, click <strong>Body</strong>. Then instead of none, select <strong>raw</strong> as the body type. Finally, on the far right of the types, change <strong>Text</strong> to <strong>JSON</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-yoda-request-body-type.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Then, in the space below it, you can add the following:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"text"</span>: <span class="hljs-string">"Hello, I am learning how to test APIs with Postman!"</span>
}
</code></pre>
<p>And now click the blue <strong>Send</strong> button again and we get a successful response!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-successful-post-body-yoda-api.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can apply this concept to pretty much any API. Postman doesn’t only permit you to post JSON, it allows you to use the other formats that we see listed in the Body Type section, meaning you have a lot of options depending on what the API you’re using requires.</p>
<h2 id="heading-part-5-authenticating-requests-to-the-lord-of-the-rings-api-with-an-api-key">Part 5: Authenticating requests to the Lord of the Rings API with an API Key</h2>
<p>For the rest of the walkthrough, we’re going to use the Lord of the Rings API.</p>
<p>First up, the Lord of the Rings API requires authentication in order to make requests using an API key. So to start, you’ll before we dive in, you’ll need to go <a target="_blank" href="https://the-one-api.herokuapp.com/sign-up">create a free account</a>.</p>
<p><a target="_blank" href="https://the-one-api.herokuapp.com/sign-up">https://the-one-api.herokuapp.com/sign-up</a></p>
<p>Once you sign up and log in, the first thing you’ll see is your API key! Either copy this key down or remember where you can find it for later. If you leave the page, you can always grab it by navigating to <strong>Welcome</strong> and then <strong>Account</strong> in the navigation of the API website.</p>
<p>To get started, let’s first create a new collection and request:</p>
<ul>
<li><strong>Collection:</strong> Lord of the Rings</li>
<li><strong>Folder:</strong> Movie</li>
<li><strong>Request:</strong> All Movies</li>
<li><strong>Request Type:</strong> GET</li>
<li><strong>Request URL:</strong> <a target="_blank" href="https://the-one-api.herokuapp.com/v1/movie">https://the-one-api.herokuapp.com/v1/movie</a></li>
</ul>
<p>Once you’re set with the above, click <strong>Send</strong>, and you’ll notice immediately it gives a response that says 401 and that it’s unauthenticated.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-unauthorized-request-lord-of-the-rings-api.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Because this API requires the API key, this is exactly what we expected. So let’s click on the <strong>Authorization</strong> tab. We can then select a <strong>Type</strong> of <strong>Bearer Token</strong>, and on the right, we can paste in our key that we just set up with the Lord of the Rings API.</p>
<p>And as soon as we hit <strong>Send</strong>, we now see a successful response!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-authorized-successful-lord-of-the-rings-api-request.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This worked really great, but what if we have a bunch of requests that use a single key. Do we have to manage that on each request?</p>
<p>Instead of managing it on each individual request, we can manage it on the collection. Let’s first build another request.</p>
<p>Under our Lord of the Rings collection and in the Movie folder, create a new request:</p>
<ul>
<li><strong>Request:</strong> Quote by Movie ID</li>
<li><strong>Request Type:</strong> GET</li>
<li><strong>Request URL:</strong> <a target="_blank" href="https://the-one-api.herokuapp.com/v1/movie/%7Bid%7D">https://the-one-api.herokuapp.com/v1/movie/{id}</a></li>
</ul>
<p>In this request, let’s use an ID from the response of the first request, I’m going to use <code>5cd95395de30eff6ebccde5b</code> which is the ID of The Two Towers, so the request URL will look like:</p>
<pre><code>https:<span class="hljs-comment">//the-one-api.herokuapp.com/v1/movie/5cd95395de30eff6ebccde5b</span>
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-inherit-authorization-from-parent.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, instead of setting our token in the request Authorization, we’re going to leave the type as <strong>Inherit auth from parent</strong>. Click on the three dots next to the collection and select <strong>Edit</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-edit-collection.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here, we’re going to do the same exact thing we did with the first request but on the Collection configuration. Select the <strong>Authorization</strong> tab, under type select <strong>Bearer Token</strong>, and in the <strong>Token</strong> field again paste your token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-add-authorization-api-key-token-to-collection.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Finally, click <strong>Update</strong> and hit the blue <strong>Send</strong> button again and we can see a successful request!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-authorized-request-inherit-token-from-parent.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can now go back to our All Movies request and update the Authorization to use a Type of Inherit auth from parent and it should still continue to work!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/postman-successful-request-lord-of-the-rings-api.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-else-can-we-do-with-postman">What else can we do with Postman?</h2>
<p>While I covered a lot of the basics, there’s quite a lot more you can do with Postman. Here are a few of my favorites.</p>
<h3 id="heading-environment-variables">Environment Variables</h3>
<p>If you’re working as a developer on a project, it’s likely that your team uses multiple environments, such as a development and production environment. Instead of creating and maintaining completely separate requests, you can add an environment variable and instead change that variable when switching between environments!</p>
<p>Variables apply to many scenarios, but that’s a common use. Check out Postman’s docs to learn how.</p>
<p><a target="_blank" href="https://learning.postman.com/docs/postman/variables-and-environments/variables/">https://learning.postman.com/docs/postman/variables-and-environments/variables/</a></p>
<h3 id="heading-import-and-export-collections-and-data">Import and Export Collections and Data</h3>
<p>A great thing about Postman is once you have your requests all organized, you can export them for others to use. This also means that you can import collections from other team members. This makes it much easier to make sure everyone’s using the same collection.</p>
<p>Bonus: you can even store these files in a Git repository, as they’re just JSON.</p>
<p>But keep in mind - if you’re using Authorization on the collection like we went over in this guide, you’ll want to make sure you don’t include that when exporting your collection.</p>
<p><a target="_blank" href="https://learning.postman.com/docs/postman/collections/importing-and-exporting-data/">https://learning.postman.com/docs/postman/collections/importing-and-exporting-data/</a></p>
<h3 id="heading-automated-testing">Automated testing</h3>
<p>Once you have a set of requests in a collection and even better, if you’re storing them in Github, you can begin to use those requests as part of a way to manage automated testing of your API.</p>
<p>While there are a few solutions for doing this, Postman includes a Collection runner built right into the app and <a target="_blank" href="https://learning.postman.com/docs/postman/collection-runs/command-line-integration-with-newman/">Newman</a> is a command line tool that lets you run tests right from the terminal.</p>
<p><a target="_blank" href="https://www.postman.com/use-cases/api-testing-automation/">https://www.postman.com/use-cases/api-testing-automation/</a></p>
<h2 id="heading-whats-your-favorite-way-to-test-and-play-with-apis">What’s your favorite way to test and play with APIs?</h2>
<p><a target="_blank" href="https://twitter.com/colbyfayock">Share with me on Twitter!</a></p>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">? Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">?️ Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Don’t Write All Your Software Tests First – Just Write One ]]>
                </title>
                <description>
                    <![CDATA[ By Alex Bunardzic Test Driven Development (TDD) is sometimes described as “writing tests first”. The TDD mantra states that we should not write code before we have written automated tests that exercise that code. Writing code first is considered subo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/dont-write-all-your-software-tests-first-just-write-one/</link>
                <guid isPermaLink="false">66d45d59b3016bf139028cf7</guid>
                
                    <category>
                        <![CDATA[ automation testing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jun 2020 05:31:23 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9a5c740569d1a4ca252b.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alex Bunardzic</p>
<p>Test Driven Development (TDD) is sometimes described as “writing tests first”. The TDD mantra states that we should not write code before we have written automated tests that exercise that code. Writing code first is considered suboptimal.</p>
<p>And of course, writing code first is how we develop software following the so-called waterfall model. In that model, we divide software development activities into stages. For example, we have a ‘requirements gathering’ stage, we have an ‘application building’ stage, we have an ‘application testing’ stage, we have an ‘application deployment’ stage and so on.</p>
<p>But how is that different from the agile methodology? Don’t we have the exact same stages in agile? </p>
<h3 id="heading-agile-methodology-vs-waterfall-methodology">Agile Methodology vs Waterfall Methodology</h3>
<p>Of course we do. The crucial difference is that in agile, those stages are not gated. </p>
<p>In waterfall, we gate the stages and execute them in strict sequence. This means we won’t begin building the shipping application until such time as the requirements have been gathered, completed, signed off on and frozen. Once requirements are frozen (and controlled by our change management policies), we move into the next stage (or phase) – application building. </p>
<p>And similarly, we won’t move into the testing stage until the entire application has been built and we have reached the code complete milestone, at which point code changes have been frozen. </p>
<p>Once code gets frozen (and code freeze is then controlled by our change management policies), we hand it off to the testers. The testing phase begins, and only once all testing has completed (and provided that no significant defects have been detected), do we move into the deployment phase.</p>
<p>In agile, we do all the above activities in parallel. At the same time. We keep working on user stories (specs) while simultaneously building the shipping application. As we’re building the application we are also testing it. And as we are building and testing the application, we are also deploying it. </p>
<p>We learn from the shipping application deployed to production and use that validated learning as the feedback that will inform new user stories. That way, the loop gets closed, and we’re iterating, improving the value incrementally.</p>
<p>The only way to enable such iterative value stream delivery is by relying on automated tests. And as we’ve described, those tests are being written very early in the game. Actually, tests must be written before we write shipping code.</p>
<p>Why then is the title of this article “Don’t Write All Your Tests First, Just Write One”? It sounds a bit confusing. Let’s unpack the meaning of this title. But first, here's an overview of what tech we'll be using:</p>
<h3 id="heading-the-technology-stack-used-for-this-exercise">The technology stack used for this exercise</h3>
<p>In the attempt to keep the exercise simple and easy to follow, I have chosen <strong><a target="_blank" href="https://dotnet.microsoft.com/">.NET Core</a></strong> platform, together with <strong><a target="_blank" href="https://xunit.net/">xUnit.net</a></strong> testing platform. To follow the coding examples, please install <code>.NET Core</code> and <code>xUnit.net</code>.</p>
<p>In order to be able to run the sample code, please open <code>./tests/tests.csproj</code> file and add this line to the <code>ItemGroup</code>:</p>
<pre><code class="lang-c#">&lt;ProjectReference Include=<span class="hljs-string">"../app/app.csproj"</span> /&gt;
</code></pre>
<p>You’re now all set for following the coding exercises.</p>
<h2 id="heading-a-simple-example">A simple example</h2>
<p>To understand the difference between writing all tests first and writing one test first, it may be better to show rather than just tell. </p>
<p>So let’s try to build a simple example – for this exercise I’ve chosen a trivial case of calculating a tip at a restaurant. Often times we find ourselves in a position where we want to tip the restaurant for the service, but it’s tough to calculate percentages in our head. So a nifty little <code>Tip Calculator</code> could come in handy.</p>
<p>Here are the expectations:</p>
<p><strong>As a patron<br>I want to calculate the total bill (total plus the tip)<br>Because I want to compliment the restaurant for the service</strong></p>
<h3 id="heading-scenario-1-patron-calculates-the-total-for-terrible-service">Scenario #1: Patron calculates the total for terrible service</h3>
<p>Given that the restaurant total is $100.00<br>And the service was terrible<br>When the tip calculator calculates the total charge<br>Then tip calculator shows $100.00 total charge</p>
<h3 id="heading-scenario-2-patron-calculates-the-total-for-poor-service">Scenario #2: Patron calculates the total for poor service</h3>
<p>Given that the restaurant total is $100.00<br>And the service was poor<br>When the tip calculator calculates the total charge<br>Then tip calculator shows $105.00 total charge</p>
<h3 id="heading-scenario-3-patron-calculates-the-total-for-good-service">Scenario #3: Patron calculates the total for good service</h3>
<p>Given that the restaurant total is $100.00<br>And the service was good<br>When the tip calculator calculates the total charge<br>Then tip calculator shows $110.00 total charge</p>
<h3 id="heading-scenario-4-patron-calculates-the-total-for-great-service">Scenario #4: Patron calculates the total for great service</h3>
<p>Given that the restaurant total is $100.00<br>And the service was great<br>When the tip calculator calculates the total charge<br>Then tip calculator shows $115.00 total charge</p>
<h3 id="heading-scenario-5-patron-calculates-the-total-for-excellent-service">Scenario #5: Patron calculates the total for excellent service</h3>
<p>Given that the restaurant total is $100.00<br>And the service was excellent<br>When the tip calculator calculates the total charge<br>Then tip calculator shows $120.00 total charge</p>
<p>Let’s now implement the above user story.</p>
<p>We see that the story has 5 acceptance criteria (a.k.a. scenarios). Now we move into the analysis phase – think about what should be the first functionality that our <code>Tip Calculator</code> application should implement. But first, let’s open the command line terminal and create the new directory:</p>
<pre><code>md TipCalculator
cd TipCalculator
</code></pre><p>and create <code>app</code> and <code>tests</code> directories inside the <code>TipCalculator</code> directory.</p>
<p>Now <code>cd tests</code> and run: </p>
<pre><code class="lang-net">dotnet new xunit
</code></pre>
<p>Then <code>cd ..</code> and <code>cd app</code>, then run: </p>
<pre><code>dotnet <span class="hljs-keyword">new</span> classlib
</code></pre><p>We’re now ready to boogie!</p>
<p>Open your favourite text editor (mine is <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a>) and set your mind on the expectations. What behaviour are we expecting from the <code>Tip Calculator</code>?</p>
<p>To narrow the scope of our expectations, it usually helps to take one acceptance criteria (i.e. one scenario) and focus on it first. Let’s take scenario #1:</p>
<h3 id="heading-scenario-1-patron-calculates-the-total-for-terrible-service-1">Scenario #1: Patron calculates the total for terrible service</h3>
<p>Given that the restaurant total is $100.00<br>And the service was terrible<br>When the tip calculator calculates the total charge<br>Then tip calculator shows $100.00 total charge</p>
<p>In case the service was terrible, we are not adding any tips, and <code>Tip Calculator</code> is calculating a $0.00 tip. So how do we automate that scenario?</p>
<p>My first expectation would be that we need to somehow inform the <code>Tip Calculator</code> that the service was terrible. We either type the word ‘Terrible’ into the input field, or we select ‘Terrible’ from the list of available service ratings. </p>
<p>So the first thing to do here is to articulate some expectations regarding <code>Tip Calculator</code>’s ability to get notified that the service was terrible.</p>
<p>I like to always start with the expectation that what the user inputs is valid. So I’d first write a test that checks if the rating ‘Terrible’ is recognized by the <code>Tip Calculator</code> as a valid rating. </p>
<p>Go to the <code>tests</code> directory, rename the autogenerated <code>UnitTest1.cs</code> file to <code>TipCalculatorTests.cs</code> and add the following test:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingTerribleIsValid</span>(<span class="hljs-params"></span>)</span>{    
  <span class="hljs-keyword">var</span> expectedResponseForValidRating = <span class="hljs-literal">true</span>;    
  <span class="hljs-keyword">var</span> actualResponseForValidRating = <span class="hljs-literal">false</span>;    
  Assert.Equal(expectedResponseForValidRating, 
  actualResponseForValidRating);
}
</code></pre>
<p>Now go to the command line, <code>cd tests</code>, and run: </p>
<pre><code>dotnet test
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-21.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Of course, the above trivial test will fail, because we have hardcoded the values. But it’s always a good practice to make sure we see our tests fail before we proceed. Not observing a test fail may give us false sense of safety later on, if no tests fail and we end up thinking that everything works as expected.</p>
<p>A few more observations about the above test:</p>
<ul>
<li>It helps if the test name is descriptive. I chose <code>CheckIfRatingTerribleIsValid</code> to communicate the fact that we must make sure our application is capable of recognizing our commands.</li>
<li>It also helps if the expected and actual variable names are descriptive. I chose <code>expectedResponseForValidRating</code> and <code>actualResponseForValidRating</code> as fairly indicative of what our expectation in this test is, and also what actual value will the <code>Tip Calculator</code> produce.</li>
<li>Test is a first-class source code and must be approached with equal care lavished upon the production code.</li>
</ul>
<h2 id="heading-first-design-decision">First design decision</h2>
<p>At this point, we are forced to make a decision – how will our nascent <code>Tip Calculator</code> know if the service rating provided by the user is valid or not? </p>
<p>The design decision that comes to mind is that <code>Tip Calculator</code> must be able to store and retrieve some data. In this case, the data we’re interested in is the service rating.</p>
<p>If we go back to the user story and review the five acceptance criteria, we will see that the expectations are that <code>Tip Calculator</code> must be able to recognize five different service ratings:</p>
<ol>
<li>Terrible</li>
<li>Poor</li>
<li>Good</li>
<li>Great</li>
<li>Excellent</li>
</ol>
<p>So the simplest way to get <code>Tip Calculator</code> to store that information would be to endow it with an array, or a list. </p>
<p>But rather than rushing in to implement that list, we should examine the expectations again, to see if there’s anything else we may have missed. And there is – not only must <code>Tip Calculator</code> be able to recognize valid service ratings, it also must be able to associate each rating with a percentage value. </p>
<p>Our analysis shows the following associations:</p>
<ol>
<li>Terrible =&gt; 0%</li>
<li>Poor =&gt; 5%</li>
<li>Good =&gt; 10%</li>
<li>Great =&gt; 15%</li>
<li>Excellent =&gt; 20%</li>
</ol>
<p>In this case, a simple array or a simple list won’t be sufficient for holding the above associations. What’s the next simplest data structure that will allow us to implement these associations? After doing a little bit of research, we figure out that <code>Hashtable</code> is probably the most fitting data structure that can cover our needs with the least amount of ceremony.</p>
<p>We now navigate to the <code>app</code> directory and rename autogenerated <code>Class1.cs</code> file to <code>TipCalculator.cs</code>. We now want to add a <code>Hashtable</code> that will hold service ratings and the associated percentage values:</p>
<pre><code class="lang-c#">System.Collections.Hashtable ratingPercentages = <span class="hljs-keyword">new</span> System.Collections.Hashtable();
</code></pre>
<p>Now is a good time to recall that TDD is focused on coupling the expectations to the application’s behaviour, not to the application’s structure. Knowing that, we need to modify our test to make <code>Tip Calculator</code> exhibit some behaviour. The test codifies some expectations with regards to how the application must behave, and the running application provides the evidence of the expected behaviour.</p>
<p>But what is the evidence of the application’s behaviour? There is no other way for us to assess and evaluate application’s behaviour other than through examining the values that the running application produces. </p>
<p>In this case, we are expecting the running application to produce values <code>true</code> or <code>false</code> (Boolean values) after we ask the application if certain value (i.e. service rating) is valid.</p>
<p>To teach the application how to behave in the expected fashion, we need to endow it with an API. In this case, we design the API as follows:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CheckIfRatingIsValid</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span>
</code></pre>
<p>In our test, we will modify the actual expected value to exercise the running application and collect the output value:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image001--1-.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see from the screenshot above, we have instantiated <code>TipCalculator</code> but when attempting to ask the instance to check if the supplied rating (“Terrible”) is valid, the editor is complaining that it cannot find that method.</p>
<p>Well of course, the method hasn’t been implemented yet. Now’s the time to go ahead and do it:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CheckIfRatingIsValid</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {    
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>Now that the method is implemented, the test works; here is the complete listing:</p>
<pre><code class="lang-c#"><span class="hljs-keyword">using</span> Xunit;
<span class="hljs-keyword">using</span> app;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">tests</span> {    
  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TipCalculatorTests</span> {        
    TipCalculator tipCalculator = <span class="hljs-keyword">new</span> TipCalculator();        

    [<span class="hljs-meta">Fact</span>]        
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingTerribleIsValid</span>(<span class="hljs-params"></span>)</span>{            
      <span class="hljs-keyword">var</span> expectedResponseForValidRating = <span class="hljs-literal">true</span>;            
      <span class="hljs-keyword">var</span> actualResponseForValidRating = 
      tipCalculator.CheckIfRatingIsValid(<span class="hljs-string">"Terrible"</span>);                  
      Assert.Equal(expectedResponseForValidRating, 
      actualResponseForValidRating);        
    }    
  }
}
</code></pre>
<p>We see from the above example that we’re cheating again (we have hardcoded return false; in our newly minted method). What’s the point of beating around the bush and merely creating skeletons and scaffoldings instead of rolling up our sleeves and doing actual coding? Let’s discuss this important topic.</p>
<h3 id="heading-discussion-about-our-first-design-decision">Discussion about our first design decision</h3>
<p>We’re illustrating here how to do TDD step-by-step. The funny part is that this step-by-step illustration is actually the exact way how we do TDD: step-by-step. There is no other way to do TDD than by doing it step-by-step. One step at a time.</p>
<p>How’s that different from any other way of doing software development? Don’t we also do everything step-by-step even when not following TDD methodology? Well, not really. Let me explain:</p>
<p>TDD to me feels like riding a galloping horse. We’re moving swiftly toward our goal, but we’re frequently touching the ground (the galloping horse is every now and then hitting the ground in order to bounce off and run fast). </p>
<p>In comparison, when I’m doing software development without TDD, it feels to me like I’m flying a kite. I’m making swift moves with the kite, but I never touch the ground, not even once. By the time I land the kite, the landing place may not be where I intended the kite to go (it’s very hard to control the direction of a kite if it’s flying in a strong wind).</p>
<p>With TDD, any time we make a change to the code (both the test code and the shipping application code), we run the tests and so we touch the ground. We are galloping, but at the same time we need this frequent grounding. We need to see whether we’re going in the right direction and also whether we’ve broken anything during our galloping. Our tests are the Oracle who keeps telling us if everything works as expected or if something started misbehaving.</p>
<p>Making changes to the code is a risky business. TDD provides a nice harness that is both guiding our design decisions and ensuring we don’t mess up something that we’ve already confirmed works to our expectations.</p>
<h2 id="heading-replace-hardcoded-value-with-actual-processing-logic">Replace hardcoded value with actual processing logic</h2>
<p>Let’s now replace the hardcoded value with actual running code. We first teach our <code>Tip Calculator</code> that there is a service rating called “Terrible” and that tip percentage associated with this rating is 0:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CheckIfRatingIsValid</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {      
  ratingPercentages.Add(<span class="hljs-string">"Terrible"</span>, <span class="hljs-number">0</span>);    
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>Our <code>Tip Calculator</code> is now knowledgeable about the fact that there is a service rating labeled “Terrible” and the tip percentage associated with terrible service is 0%. Great, but we’re still returning hardcoded value <code>false</code>. Time to replace it with actual calculation:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CheckIfRatingIsValid</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {    
  ratingPercentages.Add(<span class="hljs-string">"Terrible"</span>, <span class="hljs-number">0</span>);    
  <span class="hljs-keyword">return</span> ratingPercentages.ContainsKey(rating);
}
</code></pre>
<p>Run the test again:  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-22.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Great, but the code still looks contrived. We are loading the “Terrible” value into the instance of <code>Hashtable ratingPercentages</code> and then immediately checking to see if that value exists in the <code>Hashtable</code>. Now that we have moved from the failing test (Red) to the passing test (Green), it’s time to perform the third step in the TDD loop – Refactor.</p>
<p>Refactoring is basically the activity of modifying the code structure without affecting the code behaviour. Our task here is simple: extract the code responsible for populating of the <code>Hashtable ratingPercentages</code> into a separate block of code. </p>
<p>The most natural place for this loading is in the block of code that is doing the initialization of the <code>Tip Calculator</code> – the <code>constructor</code> method. After refactoring, our shipping application source code looks like this:</p>
<pre><code class="lang-c#"><span class="hljs-keyword">using</span> System.Collections;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span> {    
  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TipCalculator</span> {        
    <span class="hljs-keyword">private</span> Hashtable ratingPercentages = <span class="hljs-keyword">new</span> Hashtable();        
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TipCalculator</span>(<span class="hljs-params"></span>)</span> {            
      ratingPercentages.Add(<span class="hljs-string">"Terrible"</span>, <span class="hljs-number">0</span>);        
    }        

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CheckIfRatingIsValid</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {            
      <span class="hljs-keyword">return</span> ratingPercentages.ContainsKey(rating);        
    }    
  }
}
</code></pre>
<p>Run the test again, and it passes (we’re in green). We have modified the structure of the code without modifying its behaviour! Good job.</p>
<h2 id="heading-flip-the-coin">Flip the coin</h2>
<p>Any time we satisfy a positive expectation, it is a prudent practice to turn things on their head and describe the negative expectation. </p>
<p>At this point, since we’ve satisfied that a legitimate service rating value is found in the <code>Tip Calculator</code>, we want to ensure that non-legitimate values are not found in the <code>Tip Calculator</code>. </p>
<p>What do we mean by non-legitimate values? Any value other than “Terrible”, “Poor”, “Good”, “Great” and “Excellent”. Time to write the new expectation (i.e. test):</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingWhateverIsValid</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedResponseForValidRating = <span class="hljs-literal">true</span>;    
  <span class="hljs-keyword">var</span> actualResponseForValidRating =                        
  tipCalculator.CheckIfRatingIsValid(<span class="hljs-string">"Whatever"</span>);
  Assert.Equal(expectedResponseForValidRating, 
  actualResponseForValidRating);
}
</code></pre>
<p>Run the tests:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-23.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fails. As expected. (We specified that our expectation when supplying the service rating as “Whatever” should be <code>true</code>. In reality, it is <code>false</code>, because our <code>Tip Calculator</code> does not contain value “Whatever”.)</p>
<p>Fix the test (change the <code>expectedResponseForValidRating</code> from <code>true</code> to <code>false</code>) and run it again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-24.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>A moment of reflection: why did we fake the first test run and made it fail? Because we always want to make sure we observe our new test failing. That way, we’ll know that in the future any successful passing of the test is not merely a false positive.</p>
<h2 id="heading-in-praise-of-steady-state">In praise of steady state</h2>
<p>Software engineering is a balancing act between steady state and periods of unstable state. What do we mean by steady state? </p>
<p>If we have a system (a running application) that behaves the way we expect it to behave (i.e. it produces values we have specified as expected values), we declare that the system is in a steady state. It is running, and delivering some value. </p>
<p>That value delivery is still partial. In our case, the only value to the users this <code>Tip Calculator</code> delivers is its ability to recognize service rating “Terrible” as a legitimate rating. In addition, it is capable of informing us that service rating “Whatever” is not a legitimate rating.</p>
<p>That’s not much, but still is better than nothing. And good news – our running application is currently in a steady state. Now we want to look into how to add more valuable behaviour to our <code>Tip Calculator</code>. And the only way to add more value is by making some changes.</p>
<p>Any time we make a change to our application, we disturb its steady state. This disturbance is risky. It may mean our changes could break something that is already working. Because of that concern, we strive to make the duration of this unstable state as short as possible. </p>
<p>Remember how we compared TDD to riding a galloping horse? When the horse is in flight (i.e. not touching the ground) it is advancing toward our goal, but it’s not in the steady state. Only when the horse touches the ground does its state stabilize.</p>
<p>TDD encourages making small changes (in flight) and immediately grounding the system by verifying that it is back in the steady state. We value steady state despite the fact that we eagerly embrace changes. Without changes, we won’t be able to deliver value, but we must do it in a very deliberate, careful fashion. </p>
<p>When doing TDD, we treat changes to steady state like walking on eggshells. No matter how sure we may be in knowing what and how we’re doing software engineering, it is prudent to still let failing tests guide our decisions.</p>
<h2 id="heading-check-if-correct-tip-percentage-is-associated-with-service-rating">Check if correct tip percentage is associated with service rating</h2>
<p>Let’s now introduce another change into our application – a test to verify if correct tip percentage is associated with service rating “Terrible”. Remember that we populated the instance of <code>Hashtable ratingPercentages</code> with the following values:</p>
<pre><code class="lang-c#">ratingPercentages.Add(<span class="hljs-string">"Terrible"</span>, <span class="hljs-number">0</span>);
</code></pre>
<p>We have written a test that verifies that our <code>Hashtable ratingPercentages</code> does contain legitimate service rating “Terrible”. Now we need a test that verifies that service rating “Terrible” means that the tip percentage for that rating is 0.</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingTerribleHasZeroPercentTip</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedZeroPercentForTerribleRating = <span class="hljs-number">0</span>;    
  <span class="hljs-keyword">var</span> actualZeroPercentForTerribleRating = <span class="hljs-number">10</span>;    
  Assert.Equal(expectedZeroPercentForTerribleRating, 
  actualZeroPercentForTerribleRating);
}
</code></pre>
<p>The new test <code>CheckIfRatingTerribleHasZeroPercentTip</code> should fail:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-25.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Again, we’re purposefully hard coding wrong actual values just so that we could observe our brand new test fail. Now we must replace hard coded value with the actual call to the <code>Tip Calculator</code>’s method that returns tip percentage for the service rating:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingTerribleHasZeroPercentTip</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedZeroPercentForTerribleRating = <span class="hljs-number">0</span>;    
  <span class="hljs-keyword">var</span> actualZeroPercentForTerribleRating =                 
  tipCalculator.GetPercentageTipForRating(<span class="hljs-string">"Terrible"</span>);
  Assert.Equal(expectedZeroPercentForTerribleRating, 
  actualZeroPercentForTerribleRating);
}
</code></pre>
<p>As in the previous case, we have invented a new API for <code>Tip Calculator</code>. We call this new capability <code>GetPercentageTipForRating("Terrible")</code>. It takes the value of the service rating and returns the tip percentage for that rating.</p>
<p>Flip over to the <code>app/TipCalculator.cs</code> and add the hard coded skeleton of the new method:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">GetPercentageTipForRating</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {    
  <span class="hljs-keyword">return</span> <span class="hljs-number">10</span>;
}
</code></pre>
<p>Running the test fails again, because we have hard coded the return value. Let’s replace it with actual processing:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">GetPercentageTipForRating</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {    
  <span class="hljs-keyword">int</span> tipPercentage = Int32.Parse(ratingPercentages[rating].ToString());
  <span class="hljs-keyword">return</span> tipPercentage;
}
</code></pre>
<p>Run the test again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-26.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>All three tests pass – we’re in green, we’re back to steady state!</p>
<h2 id="heading-what-tip-percentage-do-we-expect-for-non-legitimate-service-ratings">What tip percentage do we expect for non-legitimate service ratings?</h2>
<p>Many years of experience in the field taught me to be a bit pessimistic. Now that we have our application back in the steady state and delivering value (answering questions about legitimate service ratings and also giving us correct tip percentage for the “Terrible” rating), we need to see what happens when we run our application by giving it non-legitimate service rating value (for example, by giving it service rating “Whatever”).</p>
<p>Time for leaving the steady state yet again. We will write another test:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingWhateverHasNegativeOnePercentTip</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedZeroPercentForWhateverRating = <span class="hljs-number">-1</span>;    
  <span class="hljs-keyword">var</span> actualZeroPercentForWhateverRating =       
  tipCalculator.GetPercentageTipForRating(<span class="hljs-string">"Whatever"</span>);
  Assert.Equal(expectedZeroPercentForWhateverRating, 
  actualZeroPercentForWhateverRating);
}
</code></pre>
<p>We are describing our expectation when <code>Tip Calculator</code> is asked to return tip percentage for service rating “Whatever”. Because service rating “Whatever” is a non-legitimate rating, we are expecting <code>Tip Calculator</code> to return tip percentage of value -1.</p>
<p>This test now precipitates one improvement to our shipping code. We need to add some logic to first check whether the supplied service rating is legitimate or not. Only if it is legitimate do we ask <code>Hashtable ratingPercentages</code> to tell us what the associated value of the tip percentage is. If the supplied service rating is non-legitimate (for example, if it is “Whatever”) we bypass talking to <code>Hashtable ratingPercentages</code> and simply return -1.</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">GetPercentageTipForRating</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rating</span>)</span> {    
  <span class="hljs-keyword">int</span> tipPercentage = <span class="hljs-number">-1</span>;    
  <span class="hljs-keyword">if</span>(CheckIfRatingIsValid(rating)) {        
    tipPercentage = Int32.Parse(ratingPercentages[rating].ToString());    
  }    
  <span class="hljs-keyword">return</span> tipPercentage;
}
</code></pre>
<p>Run the tests, and all 4 tests pass:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-27.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We are back to the steady state. Another short excursion into the volatile area, and another swift victory and a safe return to steady, imperturbable state.</p>
<h2 id="heading-populate-other-service-rating-tip-percentages">Populate other service rating tip percentages</h2>
<p>Now is a good time to take a breather and make less risky changes, following the already established pattern. Leave the safety of the steady state and make short trips into the volatile territory by adding a new test to verify if service rating “Poor” is a valid, legitimate rating:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingPoorIsValid</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedResponseForValidRating = <span class="hljs-literal">true</span>;    
  <span class="hljs-keyword">var</span> actualResponseForValidRating =       
  tipCalculator.CheckIfRatingIsValid(<span class="hljs-string">"Poor"</span>);
  Assert.Equal(expectedResponseForValidRating, 
  actualResponseForValidRating);
}
</code></pre>
<p>Running this test will fail:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-28.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Service rating “Poor” hasn’t been implemented yet. To make the test pass, implement service rating “Poor” by adding this line to the <code>TipCalculator</code> constructor:</p>
<pre><code class="lang-c#">ratingPercentages.Add(<span class="hljs-string">"Poor"</span>, <span class="hljs-number">5</span>);
</code></pre>
<p>Run the tests, and we’re back to safety:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We’re enjoying steady state with 6 tests successfully passing.</p>
<p>Now that we have added service rating “Poor” associated with the 5% tip, let’s write a test that will describe that expectation:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckIfRatingPoorHasFivePercentTip</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedZeroPercentForPoorRating = <span class="hljs-number">5</span>;    
  <span class="hljs-keyword">var</span> actualZeroPercentForPoorRating =       
  tipCalculator.GetPercentageTipForRating(<span class="hljs-string">"Poor"</span>);
  Assert.Equal(expectedZeroPercentForPoorRating, 
  actualZeroPercentForPoorRating);
}
</code></pre>
<p>The tests run successfully, and we’re back to being safe in the steady state.<br>I will leave it to the reader to make the changes that will drive the implementation of the service ratings “Good”, “Great” and “Excellent”. At the end of the exercise you should have your system back in the steady state with 12 tests successfully passing:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-35.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-calculate-grand-total-given-the-total-and-the-service-rating">Calculate grand total given the total and the service rating</h2>
<p>We are now ready for the final step – given the total bill and the service rating, we expect <code>Tip Calculator</code> to calculate tip percentage and add it to the total, producing the grand total to be paid to the restaurant.</p>
<p>As we always do, first we describe the expectation:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CalculateTotalWithTip</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> expectedTotalWithTip = <span class="hljs-number">135.7</span>;    
  <span class="hljs-keyword">var</span> actualTotalWithTip = <span class="hljs-number">200.0</span>;    
  Assert.Equal(expectedTotalWithTip, actualTotalWithTip);
}
</code></pre>
<p>As usual, we first hard code some expectations that we know are going to fail. This is so that we observe our new test failing:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-36.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Time to implement processing logic that will calculate correct total with tip. Given the total of $118.0, and the service rating “Great” (15% tip), we’re expecting the total to be $135.7:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CalculateTotalWithTip</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> rating = <span class="hljs-string">"Great"</span>;    
  <span class="hljs-keyword">var</span> total = <span class="hljs-number">118</span>;    
  <span class="hljs-keyword">var</span> expectedTotalWithTip = <span class="hljs-number">135.7</span>;    
  <span class="hljs-keyword">var</span> actualTotalWithTip = tipCalculator.CalculateTotalWithTip(total, 
  rating);    
  Assert.Equal(expectedTotalWithTip, actualTotalWithTip);
}
</code></pre>
<p>We have designed a new API the <code>Tip Calculator</code> – a method called <code>CalculateTotalWithTip(total, rating)</code>. It takes the total value and the service rating and returns the total with tip. The implementation of the method looks like this:</p>
<pre><code class="lang-c#"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateTotalWithTip</span>(<span class="hljs-params"><span class="hljs-keyword">double</span> total, <span class="hljs-keyword">string</span> rating</span>)</span> {    
  <span class="hljs-keyword">double</span> totalWithTip = <span class="hljs-number">-1</span>;    
  <span class="hljs-keyword">if</span>(CheckIfRatingIsValid(rating)) {        
    <span class="hljs-keyword">int</span> percentage = GetPercentageTipForRating(rating);        
    totalWithTip = total + ((total/<span class="hljs-number">100</span>) * percentage);    
  }    
  <span class="hljs-keyword">return</span> totalWithTip;
}
</code></pre>
<p>Run the tests, and we’re back to steady state:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-37.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-are-we-done-here">Are we done here?</h2>
<p>No, not yet. Even when all tests are in green and we’re back to the steady state, there are still a couple of things we need to do. </p>
<p>To begin with, we need to add a pessimistic expectation for our <code>Tip Calculator</code> calculation of total with the tip based on the service rating:</p>
<pre><code class="lang-c#">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CalculateTotalWithTipForNonlegitimateRating</span>(<span class="hljs-params"></span>)</span> {    
  <span class="hljs-keyword">var</span> rating = <span class="hljs-string">"Meh"</span>;    
  <span class="hljs-keyword">var</span> total = <span class="hljs-number">118</span>;    
  <span class="hljs-keyword">var</span> expectedTotalWithTip = <span class="hljs-number">135.7</span>;    
  <span class="hljs-keyword">var</span> actualTotalWithTip = tipCalculator.CalculateTotalWithTip(total, 
  rating);    
  Assert.Equal(expectedTotalWithTip, actualTotalWithTip);
}
</code></pre>
<p>Running the tests produces one failing test:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-38.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our expectation for non-legitimate service rating (“Meh”) was incorrect. The actual total is -1, so we need to adjust our expectation by replacing 135.7 with -1. Run the tests again, and we’re back to the steady state!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-39.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We now have 14 tests, they all successfully pass, and our <em>Tip Calculator</em> works according to our expectations and satisfies the acceptance criteria.</p>
<p>We’re almost done. One more sanity check before we can confidently ship our shiny new <code>Tip Calculator</code> – we must run <em><a target="_blank" href="https://opensource.com/article/19/9/mutation-testing-example-definition">mutation testing</a></em>. </p>
<p>Our mutation testing framework will mutate the shipping code, one line at a time, and will run all tests for each individual mutation. </p>
<p>If the tests complain about the mutated code, all is good, we have killed the mutant. If the tests don’t complain, we’re in trouble. We have a surviving mutant in our codebase, which means there are lines of code in our repo that are doing something for which we haven’t provided any expectations.</p>
<p>Let’s run mutation testing to see how solid our solution is. Good news – our solution has killed 100% of mutants!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-40.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Mutation testing has given our shipping application a clean bill of health. Our <code>Tip Calculator</code> seems to be in good shape.</p>
<h2 id="heading-red-green-refactor-reflect">Red-Green-Refactor-Reflect</h2>
<p>Let’s review our <code>Tip Calculator</code> building exercise. We started the process by describing our expectations using the classical user story format. User story (as the name implies) is focused on describing scenarios that fulfill end user’s goals. </p>
<p>In this case, the simple goal is to calculate the tip amount from the supplied service rating and the restaurant bill total. The calculated tip amount is then automatically added to the total.</p>
<p>From there we proceeded to build our shipping application by following the TDD methodology. As we’ve demonstrated, the methodology consists of writing a failing test, observing it fail (the Red phase of TDD), then immediately making code changes that ensure the test passes (the Green phase of TDD). Once the test passes, we move into the Refactor phase (we restructure the code without affecting its behaviour). That way, we make sure our code is not expensive to change.</p>
<p>A proper TDD practice also mandates frequent retrospective – we call it reflection. We stop and think about the things we’ve accomplished thus far, to see if we could learn from our recent experiences. This reflection fortifies the process, as it relies on frequent and tight feedback provided by the failing, then succeeding tests.</p>
<p>I have already compared Test Driven Development to the experience of riding a galloping horse. While riding a horse, we’re alternating between flying through the air (i.e. speed achieved when the horse leaps from the ground) and steering the horse. It is impossible to steer the horse while we’re off the ground, up in the air. At that point, we gain speed, but we cannot make any changes of the direction. It is only once the horse touches the ground that we can make a change in direction.</p>
<p>In TDD, we strive to touch the ground as frequently as possible. The longer the leaps we make without touching the ground, the less chance we have for correcting the course.</p>
<p>I also compared software development practices that don’t follow TDD principles to the experience of flying a kite. When flying a kite, we never touch the ground. It is an exhilarating feeling of letting the wind pick the kite up and bounce it up in the air. We can achieve considerable speed that way. But we struggle in such situations to maintain desired course. And after we eventually land the kite, it usually does not land in the spot we originally wanted it to land.</p>
<p>Why is the emphasis of this article on “don’t write tests first”? Many software engineers who are not familiar with agile practices as implemented in TDD usually either claim that writing automated tests isn’t necessary, or claim that automated tests should be written after the code is complete. </p>
<p>Once they start learning about agile and TDD, they may reconsider their practices and decide that writing tests before writing implementation code may make more sense. Still, because of the ingrained waterfall mentality, some of those engineers make the mistake of writing all tests first, and only then move into writing the code.</p>
<p>That approach is completely wrong. It is equivalent to the traditional waterfall approach where we go through the development process by respecting gated phases. </p>
<p>First we write the requirements (in this case, requirements would be expectations written in the form of automated tests). Only once all the requirements (i.e. automated tests) have been written, signed off and frozen, do we move into the next gated phase – write the code for the shipping application.</p>
<p>TDD is the exact opposite of the “write tests first” approach. In TDD, we always write only one test. That test describes a desired behaviour. The desired behaviour does not exist yet (that’s why it is desired), and the test fails. </p>
<p>We then immediately move into making changes to the code in the attempt to create the desired behaviour. Once desired behaviour is created, it gets validated by the test, and if the expectations of the test are satisfied, we move into refactoring the code (to satisfy nonfunctional requirements, such as cost of change).</p>
<p>We practice a rigorous discipline to never succumb to the temptation to write more than one test at a time. That way, we ensure that we keep touching the ground as frequently as possible. </p>
<p>We prefer to remain ‘in flight’ for the shortest possible time. We are ‘in flight’ during that period when the desired behaviour described in the test has not materialized yet. The smaller the expected and desired behaviour is, the shorter will be our ‘in flight’ trajectory. That way, we keep touching the ground often, which gives us a chance to adjust the steering.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a simple <code>Tip Calculator</code> is a toy sized problem, and using that exercise to illustrate TDD methodology is not necessarily providing a convincing argument in favour of TDD. Still, within the constraints of a technical article, going over this hands-on exercise may provide valuable insights into the benefits of adopting TDD.</p>
<p>We would still argue that the real benefits of TDD only become apparent when dealing with much larger, more complex software engineering efforts. The ability to remain grounded while making potentially risky changes to a large, complex system is often a life saver. </p>
<p>In addition to that, building software using TDD methodology results in much less rework. TDD drives high degree of modularization, which results in high cohesiveness of the modules and low coupling between the modules. </p>
<p>All these characteristics produce a shipping application whose codebase is easy and inexpensive to change. And lowering the cost of change has proven to be the best way on the path to embracing changes and abandoning the concept known as ‘scope creep’. </p>
<p>Bottom line, TDD enables software engineering teams to deliver high degree of flexibility to the business.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Software Quality Assurance Guide ]]>
                </title>
                <description>
                    <![CDATA[ Quality Assurance Quality Assurance (commonly known as QA) is the means by which a product in development is checked to make sure it works as it’s supposed to. The actual methods used in QA processes vary hugely depending on the size and nature of th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/software-quality-assurance-guide/</link>
                <guid isPermaLink="false">66c35f21c337fbd10a4b5968</guid>
                
                    <category>
                        <![CDATA[ QA ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ toothbrush ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 01 Mar 2020 19:48:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9c58740569d1a4ca3194.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="heading-quality-assurance"><strong>Quality Assurance</strong></h2>
<p>Quality Assurance (commonly known as QA) is the means by which a product in development is checked to make sure it works as it’s supposed to. The actual methods used in QA processes vary hugely depending on the size and nature of the product.</p>
<p>For a personal project you will probably just test as you go, asking others to provide feedback at appropriate stages. By contrast, a banking application must have every aspect of every feature exhaustively checked and documented to ensure it is both functional and safe.</p>
<p>Regardless of how formal or detailed a QA process is, its aim is to identify bugs so they can be resolved before the product is released.</p>
<h2 id="heading-methodologies">Methodologies</h2>
<h3 id="heading-agile">Agile</h3>
<p>In an Agile approach to development, the aim is that each cycle of work (‘sprint’) produces working software that can be added to and improved upon iteratively. This makes the QA processes an intrinsic part of the development cycle. </p>
<p>By testing software components at each stage of their production you reduce the risk of bugs being present at release.</p>
<h2 id="heading-terminology">Terminology</h2>
<h3 id="heading-automation-testing">Automation Testing</h3>
<p>Testing done with pre-written scripts designed to control the execution of tests.</p>
<h3 id="heading-black-box">Black Box</h3>
<p>These test do not look inside the system under test, but treat it as ‘closed’ in the same way that the end user will experience it.</p>
<h3 id="heading-defect">Defect</h3>
<p>Any deviation from an application’s specifications; often referred to as a “bug”.</p>
<h3 id="heading-exploratory-testing">Exploratory Testing</h3>
<p>An unscripted approach to testing, which relies on the tester’s unique creativity in an effort to find unknown bugs and identify regressions.</p>
<h3 id="heading-integration-testing">Integration Testing</h3>
<p>Testing individual components/modules together to ensure they connect and interact well with one another.</p>
<h3 id="heading-negative-path-testing">Negative Path Testing</h3>
<p>A testing scenario designed to produce an error state in a feature/application and verify that the error is handled gracefully. An example of this is inputing a series of numbers in the email field in a user registration form and checking to make sure the registration is not accepted until an actual email address is provided.</p>
<h3 id="heading-regression-testing">Regression Testing</h3>
<p>Testing done on a new build to ensure that new functionality has not unintentionally broken previously tested functionality.</p>
<h3 id="heading-smoke-tests">Smoke Tests</h3>
<p>A minimalistic approach to testing intended to ensure basic functionality is working before more in-depth testing takes place. Typically occurs at the beginning of the testing process.</p>
<h3 id="heading-test-case">Test Case</h3>
<p>Specified preconditions, steps, and expected results referred to by a QA tester/engineer to determine whether or not a feature performs its task as expected.</p>
<h3 id="heading-white-box">White Box</h3>
<p>Refers to tests performed at a structural level, within the codebase. Programmers checking that the inputs to and outputs from specific functions or components would be white box testing.</p>
<p>Also known as ‘Glass Box’, ‘Clear Box’, ‘Transparent Box’ because the tester can ‘see inside’ the system under test.</p>
<p>Main categories are</p>
<ul>
<li><strong>Unit tests</strong> (individual units of code do what they should)</li>
<li><strong>Integration tests</strong> (units/components interact with each other properly)</li>
<li><strong>Regression tests</strong> (re-applying tests at later stages of development to ensure they still work)</li>
</ul>
<p>There are three main techniques:</p>
<ul>
<li><strong>Equivalence partitioning</strong> (the tested input values are representative of larger input datasets)</li>
<li><strong>Boundary Value Analysis</strong> (the system is tested with chosen inputs where behaviour and therefore output should change)</li>
<li><strong>Cause-Effect Graphing</strong> (tests are designed from a visualization of the input-output relations)</li>
</ul>
<h3 id="heading-other-resources"><strong>Other Resources</strong></h3>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-write-qa-documentation-that-will-work/">How to write QA documentation that actually works</a></li>
<li><a target="_blank" href="https://guide.freecodecamp.org/agile/test-driven-development">Test Driven Development</a></li>
<li><a target="_blank" href="https://guide.freecodecamp.org/software-engineering/unit-tests/">Unit tests</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Test-driven development might seem like twice the work — but you should do it anyway ]]>
                </title>
                <description>
                    <![CDATA[ By Navdeep Singh Isn’t Test Driven Development (TDD) twice the work? Should you do it anyway? The short answer to the first question is NO. On the surface, it may seem like without TDD, time is only required to create the feature. With TDD, you need ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/isnt-tdd-test-driven-development-twice-the-work-why-should-you-care-4ddcabeb3df9/</link>
                <guid isPermaLink="false">66c3589271e87702d4e5b6ea</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 17 Aug 2017 11:25:44 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*C1mf126YNJHmaaMUbaYYyQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Navdeep Singh</p>
<p>Isn’t Test Driven Development (TDD) twice the work? Should you do it anyway?</p>
<p>The short answer to the first question is <strong>NO</strong>. On the surface, it may seem like without TDD, time is only required to create the feature. With TDD, you need time to create the test AND create the feature, thus doubling the development time required.</p>
<p>What you’re not considering is the amount of time required for QA testing and debugging when the feature isn’t performing properly.</p>
<blockquote>
<p>Case studies were conducted with three development teams at Microsoft and one at IBM that adopted TDD. The results of the case studies indicated that the pre-release defect density of the four products decreased between 40% and 90% relative to similar projects that did not use the TDD practice.</p>
<p>Subjectively, the teams experienced a 15–35% increase in initial development time after adopting TDD. (<a target="_blank" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2009/10/Realizing-Quality-Improvement-Through-Test-Driven-Development-Results-and-Experiences-of-Four-Industrial-Teams-nagappan_tdd.pdf">source</a>)</p>
</blockquote>
<p>That 40–90% decrease in pre-release defects means that QA teams and customers weren’t finding and reporting those issues. Engineering wasn’t trying to recreate bugs and develop patches, all of which have associated costs.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/rsCNd3MzBvEUjx9bQ-QYiXjG1vaZ4V35yZCr" alt="Image" width="522" height="269" loading="lazy">
<em>Number of Iterations per task</em></p>
<p>When discussing TDD, we consider a task to be a subset of a requirement that can be implemented in a few days or less. TDD software engineers develop production code through rapid iterations, as shown in the figure above.</p>
<h3 id="heading-what-is-tdd">What Is TDD?</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JWJWnEz2BCL7beWEwIlBRSKv4Qretm6OXGtn" alt="Image" width="489" height="511" loading="lazy"></p>
<p>Test-Driven Development is an approach to writing software in which the developer uses specifications to shape the way they implement a feature. For short, we describe it as the “red-green-refactor cycle”.</p>
<p>Before writing any code that adds new functionality to an application, the developer first writes an automated test describing how the new code should behave, and watches it turn red (fail to pass). They then write the code to the specification, and the test turns green (it passes). Finally, the developer takes a little time to make sure that the code just written is as clean as possible (refactoring).</p>
<h3 id="heading-why-you-should-care-about-tdd">Why you should care about TDD</h3>
<p>Automated testing gives your software developers the confidence to make changes to the software and to know that no bugs were created as a byproduct.</p>
<p>Additionally, it allows more agility for developers who aren’t familiar with the details of the software to confidently modify the source code without introducing errors.</p>
<p>Let’s discuss some really cool advantages of TDD.</p>
<h4 id="heading-1-tdd-helps-you-prevent-bugs">1. TDD Helps You Prevent Bugs</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/FOKSPU5-luiwfkdcFbOqWqRWYBhJyD3TwncA" alt="Image" width="638" height="479" loading="lazy"></p>
<p>First, test suites ensure comprehensive test coverage of the codebase, so bugs are less likely to pop up unnoticed. Second, test suites allow developers to work out potential issues before the application is ready to go into production. Finally, because test suites are constantly maintained, they guarantee software quality.</p>
<h4 id="heading-2-self-explanatory-code-well-documented">2. Self Explanatory code (well-documented)</h4>
<p>Because refactoring code is a built-in step in TDD, you end up with a much cleaner codebase as you go. Apps built with TDD tend to have less duplication, fewer edge cases that aren’t thought through, and a better overall architecture.</p>
<p>The test serves as a specification for what the code that will be written should <strong>do</strong>. As long as you’re writing good stories, your development team should be able to build exactly what you asked for. If your team agrees to use <a target="_blank" href="https://en.wikipedia.org/wiki/Test-driven_development#TDD_and_ATDD">Acceptance Test-Driven Development</a>, you can even write tests that describe how you want it to work in plain English!</p>
<h4 id="heading-3-avoid-the-bugger-debugger-problem">3. Avoid the bugger debugger problem</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/VFYfcFvkkNINz-pUynhdPkrrXDXYwt6SKECJ" alt="Image" width="800" height="470" loading="lazy"></p>
<p>Typically, when talking tech about software development, there are two main types of testing that can be integrated: functional and non-functional. These two types of testing practices are further divided into numerous types of testing techniques as you can see here:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/U4QtKTWFv4bTw1VsmXZTSIfgG2xPwz7gBLTx" alt="Image" width="580" height="341" loading="lazy">
<em>And the list goes on</em></p>
<p>It becomes really important to strategize the testing plan before project commencement, since that helps in clearly defining the roles and responsibilities of developers with respect to testers when it comes to testing.</p>
<p>For example:</p>
<ul>
<li>Unit and Integration tests to be performed by developers before handing out builds to testers</li>
<li>User acceptance testing to be performed by the testers</li>
<li>Performance testing and UI testing should be done by both</li>
</ul>
<p>A brief description of a few very important testing methodologies from the diagram above, that should be included in almost every test plan, are covered below.</p>
<p><strong>Unit Testing</strong> involves testing individual units of source code to determine if they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. <a target="_blank" href="https://www.martinfowler.com/articles/mocksArentStubs.html"><strong>Faking, Mocking, and Stubbing</strong></a> <strong>are indispensable while writing unit tests for code which has API interactions<em>.</em></strong></p>
<p><strong>Integration testing</strong> involves a combination of two or more “units” being tested. Integration tests verify that the components of the software all work together or “integrate” appropriately.</p>
<p><strong>Performance testing</strong> is used to ensure that software applications will perform well under their expected workload. The features and functionality supported by a software system are not the only concerns. A software application’s performance, like its <strong>response time, reliability, resource usage,</strong> and <strong>scalability</strong>, matters<strong>.</strong> The goal of performance testing is not to find bugs, but to eliminate performance bottlenecks.</p>
<h4 id="heading-4-you-can-forecast-troubles">4. You can forecast troubles</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KGS6NPx9YOIVplTrknkvNnydeZpmVo9pdtPZ" alt="Image" width="300" height="294" loading="lazy">
<em>A solid TDD approach alarms you about troubles upfront</em></p>
<p>The benefit of a comprehensive test suite is that it alerts you to changes early. For example, if your checkout flow stops charging users’ credit cards, you’ll know it right away, because the tests will fail. It also means that if someone makes a mistake and something doesn’t work the way it was supposed to, it will be obvious.</p>
<p>This is good, because it will give you a chance to fix it before it goes to production. If it becomes necessary down the road, you can even start a campaign of deep refactoring without fear, because you’ll have an ironclad test suite that will remain green.</p>
<h4 id="heading-5-save-money">5. Save Money</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/dCY0sc49bVWFBMBR5Fk-dKyUTTjEEnwDBvMw" alt="Image" width="800" height="533" loading="lazy"></p>
<p>When code is complicated, it gets much harder to get anything done — one little change over here can result in a big problem over there. When following TDD, developers can make changes with confidence and your QA team will catch fewer regressions. In development speak, <strong>“time saved is equal to money earned.”</strong></p>
<h4 id="heading-6-invest-the-saved-time-in-innovations-and-research">6. Invest the saved time in innovations and research</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/u7Z0aFmVNsdtWOYuf2Z80vDXQKgG1DfuL83g" alt="Image" width="480" height="225" loading="lazy">
<em>Spend the saved time in innovation</em></p>
<p>If we just adopted a TDD approach, much of this money (time saved as expressed in point 5) could be spent on new innovations instead.</p>
<h4 id="heading-7-tdd-helps-you-avoid-scope-creep"><strong>7. TDD Helps You Avoid Scope Creep</strong></h4>
<p>The nightmare of any project manager is scope creep — any unexpected growth in the scope of work which leads to delays in project delivery.</p>
<p>Scope creep can happen for various reasons: poorly defined tasks, misinterpretation of project requirements, lack of documentation, and so on. There are many methods aimed at mitigating scope creep, and TDD is one of them.</p>
<p>Thanks for reading! Please share it if you found it useful :)</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
