Writing unit tests with Python unittest

Python 3 provides a really nice and quite a featured library that allows us to write unit tests for our applications. This library, known as unittest, is used for writing unit tests that may range from the complexity of very simple tests to very complex tests involving a proper setup before a unit test is made to run.

Some of the features that we see supported in the Python unittest library are as follows:

  • Object-oriented: The library facilitates the writing of unit tests in an object-oriented manner. What this means is that, the objects are written in an object-oriented form through the use of classes and methods. This in no sense means that only object-oriented code can be tested with the library. The library does support testing object-oriented and non-object-oriented code alike.
  • Ability for test fixtures: Some of the tests may require the environment to be set up in a certain way before the test is run and then cleaned up properly once the test completes execution. This is known as test fixture and is fully supported by the Python unittest library.
  • Ability to write test suites: The library provides the functionality for writing fully featured test suites that are composed of multiple test cases. The results of a test suite are aggregated and displayed at once.
  • Built-in test runner: A test runner is used to orchestrate the tests and compile the results of the executed tests to generate a report. The library provides a built-in test runner to achieve this functionality.

Now, let's take a look at following code, which we will use to write our unit tests on:

import hashlib
import secrets

def strip_password(password):
"""Strip the trailing and leading whitespace.

Returns:
String
"""
return password.strip()

def generate_salt(num_bytes=8):
"""Generate a new salt

Keyword arguments:
num_bytes -- Number of bytes of random salt to generate

Returns:
Bytes
"""

return secrets.token_bytes(num_bytes)

def encrypt_password(password, salt):
"""Encrypt a provided password and return a hash.

Keyword arguments:
password -- The plaintext password to be encrypted
salt -- The salt to be used for padding

Returns:
String
"""

passwd_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 10000).hex()
return passwd_hash

In this code, we have defined some functions that aim to help us with the generation of the password hash that can than be safely stored inside the database.

Now, our aim is to utilize the Python unittest library to write some unit tests for the preceding code.

The following code aims to implement a small set of unit tests for the passwords helper module:

from helpers import strip_password, encrypt_password
import unittest

class TestPasswordHelpers(unittest.TestCase):
"""Unit tests for Password helpers."""

def test_strip_password(self):
"""Test the strip password function."""

self.assertEqual(strip_password(' saurabh '), 'saurabh')

def test_encrypt_password(self):
"""Test the encrypt password function."""

salt = b'xf6xb6(xa1xe8x99rxe5xf6xa5Qxa9xd5xc1xadx08'
encrypted_password = '2ba31a39ccd2fb7225d6b1ee564a6380713aa94625e275e59900ebb5e7b844f9'

self.assertEqual(encrypt_password('saurabh', salt), encrypted_password)

if __name__ == '__main__':
unittest.main()

We created a simple file for running our unit tests. Now, let's take a look at what this file does.

Firstly, we import the functions that we want to test from their required module. For this example, we have these functions defined inside a file named helpers.py from which we are going to import them. The next import gets us the Python unittest library.

Once we have the required things imported, the next step is to start writing the unit tests. To do this, we start with defining a class named TestPasswordHelpers that inherits from the unittest.TestCase class. The class is used to define a set of test cases that we may want to execute, as follows:

class TestPasswordHelpers(unittest.TestCase):

Inside the class definition, we then move on to defining individual test cases for the methods that we want to test. The methods that define a test case must start with the word test so as to signify that this particular method is a test and needs to be executed by the test runner. For example, the method that is responsible for testing our strip_password method is named as test_strip_password():

def test_strip_password(self):

Inside the method definition, we are using assertions to validate if the output of a particular method is what we expected or not. For example, the assertEqual method is used to assert whether the parameter 1 matches with the parameter 2 or not:

self.assertEqual(strip_password(' saurabh '), 'saurabh')

Once these tests have been defined, the next thing to do is define an entry point for our test file when it is run through the Terminal. This is done by calling the unittest.main() method from the entry point. Once the call is made, the test cases mentioned in the file are run and an output is displayed, as follows:

python helpers_test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.020s

OK

This is as easy as it can get when you want to write unit tests with Python. Now, it's time for us to move on to something that is more important. Let's write some unit tests for our demo application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.5.57