Beginner’s Guide on Unit Tests: What, Why and How?

  • 31st Mar, 2024
  • Dhanashree K.
Share
  • LinkedIn-icon
  • WhatsApp-icon

Beginner’s Guide on Unit Tests: What, Why and How?

31st Mar, 2024 | Dhanashree K.

  • Software Development
Unit Tests

Have you ever made a small change in form validation, tested it, deployed it, and then broken the next few pages or end points of your API?

Do you know why this might have happened or how to avoid it?

Unit Tests are your answer!!!

A unit test is a small piece of code that will test different parts of your project to verify if they are working as expected.

A unit test for the frontend can check if components are being rendered correctly if optional and conditional fields of a form appear as and when expected, and buttons are activated after correct validations, the list can go on endlessly.

For the backend, it can be to check if data upload works correctly if endpoints are sending the response in the correct format and order, the values and their types are as expected.

Let's say you make a small change and realize that it may affect 5 to 6 endpoints or pages, this will mean that you will manually test all the endpoints or pages and forms.

To do this you will need to set up your database with testing entities, populate them, update them, delete them, etc.

You spend half a day setting up, testing, and deploying it after which your QA will also need to spend a considerable amount of time to test all the affected modules.

The way to be fairly certain that nothing will break is to always write unit tests for every new feature, module, or change that you make, as soon as you make them.

This way all your existing modules and pages get tested before you push your code.

Advantages of Writing Unit Tests

1. Reliability

If you have a healthy collection of tests (provided you are not lazy) then just running tests after making changes will ensure that all your existing work still works (pun intended).

2. Saves time

Unit tests save time for setting up the environment and database for the tests manually every single time.

3. Customizable for every need

One can write tests for the smallest to the biggest things like checking the cases or spaces in response messages to testing if data is uploaded from Excel and complicated calculations are being done correctly.

Or in the case of the front end, one can test from the color of the headers to the conditional rendering of components.

4. Consistency

Tests the old code and also catches errors if you change any project-wide utility functions.

Example: The function celcius_to_farenheit(temp_celcius) now returns results up to 2 pt (assume previously returned 4 pt precision).

Now some of the previous use cases using 4pt precision will fail and from the failing tests you will be made aware of all the places this change is affecting.

5. Early Bug Detection

Unit tests facilitate the early identification of bugs during the development process, as they are crafted prior to the actual implementation of code.

This practice ensures prompt detection and resolution of issues, thereby minimising the expenses associated with bug fixing in later developmental phases.

Disadvantages of Writing Unit Tests

Honestly, I believe there aren't any, except that initially, it may feel time-consuming, but as you get the hang of it and realize how to make test cases it will become a small but important step in your SDLC.

Writing Unit Tests

Keep in mind that test folders and test functions must start with “test_” in Python and in react they must end with “.test.js”.

For starters (and my own bias) let's start with tests for Python code using the popular and powerful testing framework Pytest.

The first step to any testing, automated or manual, is to set up.

Here I must introduce you to fixtures.

Pytest’s fixtures feature permits developers to feed data into the tests.

For example, say we have several tests that all make use of the same data then we can use a fixture to pull the repeated data using a single function.

In Python, we use the assert keyword to check if a given condition is True.

Create a tests folder inside your app and add a conftest.py file which should look something like the code below.

@pytest.fixture(scope='session')
def app():
#Initialise the new application instance for the testing
# define or set up your app…
application.config.update({
        'TESTING': True,
    })
    application.config.update({
        'SQLALCHEMY_DATABASE_URI': config_data.get('SQLALCHEMY_TEST_DATABASE_URI')
    })
    with application.app_context():
        db.init_app(application)
        db.create_all()
yield app

@pytest.fixture(scope='session')
def testing_client(app):
#This method is being used to fetch the app object to test the general #user test cases. At the end of the session, the User is deleted from #cognito user pool.
	
yield app.test_client()


The snippet above creates a test client that we can use to query the local testing server while running tests.

Inside the testing client, one can perform all sorts of setups like creating a sample user’s profile in the DB, populating sample testing data, etc.

Now we want to see if a RESTful API endpoint returns a certain response.

We can write a test to check that.

def test_say_hello_positive(testing_client):
   expected_response = { 'status': True, 'message': ‘Hello’}
   api_response = org_admin_client.get(
       '/api/v1/greet/hello', content_type='application/json' )
   assert validate_status_code( expected=200, received=api_response.status_code)
   assert validate_response( expected=expected_response, received=json.loads(
           api_response.get_data()) )

In the above snippet:

  • We first define the expected response from the endpoint.
  • Then we make a call to the local test server.
  • We then compare the HTTP response codes to see if they match.
  • If yes, then we pass the actual response and expected response through a recursive function called validate_response that will go through the keys and their values of both responses and match the keys for their values and type. If they mismatch then it returns false and the test fails.
  • We will write the validate_response and validate_status_code functions in the conftest file and then they can be imported them from the conftest file to be reused in all tests.

To run such tests you need to use the pytest command in your terminal, the following are some ways to do that:

  • Just one single test, use the following command:
pytest tests/test_users.py:: test_say_hello_positive

  • For all at once, you can use:
pytest
  • From only one particular file, run:
pytest tests/test_users.py

To check the adequacy and sufficiency of the tests written by us we can use the coverage package to check how much code our tests are “covering”.

  • Install using pip
  • And run the command given below:
coverage run -m --source=app/views pytest && coverage report --fail-under=50

  • Set coverage percentage requirement using the fail_under setting.

Since we are covering Python and Django is a rather popular use, we will see some basic snippets for Django’s own TestCase package.

Here instead of fixtures, we use the setup function which can be test case specific or you can create a reusable one for multiple tests.

from Django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
   def setUp(self):
       Animal.objects.create(name="cat", sound="meow")
   def test_animals_can_speak(self):
       cat = Animal.objects.get(name="cat")
       self.assertEqual(cat.speak(), 'The cat says "meow"')

In case you are using Django’s TestCase to write tests, the following are some commands to run them:

  • Run all the tests in the particular module:
$ ./manage.py test animals.tests
  • Run just one test case:
$ ./manage.py test animals.tests.AnimalTestCase

  • Run just one test method:
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak

It is only fair that we cover unit testing in a frontend framework as well, so let's take a small example from React.

JEST Framework is one of the popular JS testing frameworks for React and comes with React, which can be verified from your project’s package.json.

To run tests: jest –watch Or in React you can use the command npm test run

Let’s say you wish to check the heading of your Login Component which looks like this.

function Login(){
.
.
return(
       <>
<div className="login_block">
           <h2 data-testid = 'login'>Please Enter Username and Password</h2>
           //form…..         
           </div>
       
       </>
   )
}
export default Login

We can test the Login component’s heading using the snippet given below.

First, create a test folder in your src, add a file named login.test.js and paste the snippet inside it.

import { render, screen } from '@testing-library/react'
import Login from './components/login;
test("login heading", () => {
   render(<Login/>);
   const element = screen.getByText(/Please Enter Username and Password/i);
   expect(element).toBeInTheDocument();
})

Let’s break down the above snippet line by line:

  • render and screen functions from the @testing-library/react are used for rendering components and to query the elements in the rendered component.
  • The test function takes the name of the test we are creating and assigns a callback to it.
  • Inside the test, we are rendering the login component.
  • We get it by searching the text of the login heading into the constant element.
  • The expect statement will check if this element is present in the DOM and fail or pass the test accordingly.

I hope these basic examples help you out with starting your unit testing journey.

Happy coding!!!

More blogs in "Software Development"

Terraform
  • Software Development
  • 28th Mar, 2024
  • Dhyey B.

Unveiling the Power of Terraform: A Beginner’s Guide

Image source: Terraform Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp. It allows users to define and provision infrastructure using a declarative...
Keep Reading
App Development
  • Software Development
  • 30th Apr, 2021
  • Hardik D.

Wearable Watch App Sync with Mobile Device

What are You Going to Learn? Built a little interface for Apple Watch using WKInterfaceController. Transferring data from iPhone to Apple Watch is very similar to...
Keep Reading
SaaS A Comprehensive Guide to Software as a Service
  • Software Development
  • 18th Jul, 2023
  • Rinkal J.

SaaS: A Comprehensive Guide to Software as a Service

In order to keep pace with the rapid pace of digital transformation in today's world, organizations frequently explore creative methods of streamlining their operations and...
Keep Reading