Open In App

Typical directory structure for running tests using unittest in Python

Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will take a look at the typical directory structure for running tests using unittest in Python.

What is the unittest module in Python?

The unittest module is a built-in Python library that is used for testing the functionality of individual units of source code. It is a powerful tool that allows developers to write and run repeatable tests, which can help to ensure that their code is working as intended and that it remains reliable over time.

The unittest module provides several key features, including:

  • The ability to define test cases and test suites, which can be used to group together related tests
  • A set of assert methods that can be used to verify that code is behaving as expected
  • Support for running tests in parallel, which can help to speed up the testing process

Before we dive into the specifics of the directory structure, it’s important to understand some key concepts related to unittest.

  • Test Case: A test case is an individual unit of testing. It consists of a set of inputs and the expected output or behavior for those inputs. Test cases are written using the unittest module, and are typically stored in separate files from the main codebase.
  • Test Suite: A test suite is a collection of test cases that are run together. Test suites allow you to group related test cases and run them as a single unit.
  • Test Runner: A test runner is a tool that executes the test suite and displays the results. There are several test runners available for Python, including the built-in unittest runner and third-party tools such as pytest.

The typical directory structure for running tests

Here is a typical directory structure for organizing tests using unittest in a Python project:

project/
├── package/
│   ├── __init__.py
│   ├── module.py
├── tests/
│   ├── __init__.py
│   ├── test_module.py
├── setup.py
  • project/ is the root directory of your Python project. It contains all of the files and subdirectories related to your project.
  • package/ is a subdirectory that contains code for a Python package. A package is a collection of modules that can be imported and used in other Python programs. The __init__.py file is a special file that tells Python that this directory should be treated as a package. The module.py file is a Python module that contains code that can be used by other parts of your project.
  • tests/ is a subdirectory that contains test code for your project.
  • setup.py is a Python script that is used to install your project. It specifies metadata about the project, such as its name, version, and dependencies, and defines the entry points for your project.

Implementation of running tests using unittest in Python:

Here is an example of a complete working code that we can use to test the unittest module in Python:

We are going to have two different files math_functions.py which contain different mathematical functions and test_math_functions.py which contains tests related to math_functions.py. We are not creating that typical structure because we are taking a simple example of running tests using unittest in Python.

math_functions.py: In this code, we are defining some mathematical functions.

Python3




# math_functions.py
def addition(a, b):
    return a + b
 
def subtraction(a, b):
    return a - b
 
def multiplication(a, b):
    return a * b
 
def division(a, b):
    return a / b


test_math_functions.py: In this code we have written our main program to test the function present in math_functions.py

Python3




# test_math_functions.py
 
import unittest
from math_functions import *
 
# Define class to test the program
class TestMathFunctions(unittest.TestCase):
    # Function to test addition function
    def test_addition(self):
        result = addition(2, 2)
        self.assertEqual(result, 4)
         
    # Function to test addition function
    def test_subtraction(self):
        result = subtraction(4, 2)
        self.assertEqual(result, 2)
         
   # Function to test addition function
    def test_multiplication(self):
        result = multiplication(2, 3)
        self.assertEqual(result, 6)
         
    # Function to test addition function
    def test_division(self):
        result = division(4, 2)
        self.assertEqual(result, 2)
 
if __name__ == '__main__':
    unittest.main()


Explanation:

  1. Firstly we will import unittest module.
  2. The math_functions module is imported. This module should contain the functions being tested.
  3. A new class called TestMathFunctions is defined. Which is a class that provides a number of assert methods for testing.
  4. Four test methods are defined in the TestMathFunctions class: test_addition, test_subtraction, test_multiplication, and test_division. These methods test the corresponding functions in the math_functions module.
  5. In each test method, the function being tested is called with specific input arguments. The result of the function is then checked using the assertEqual method, which checks that the result is equal to the expected output. If the result is not equal to the expected output, the ‘assertEqual’ method will raise an error, causing the test to fail.
  6. The if __name__ == ‘__main__’: block at the bottom runs the test suite when the script is run. The unittest.main() function is called, which runs the tests in the TestMathFunctions class.

To run this code, first, save the “math_functions.py” file and the “test_math_functions.py” file in the same directory. Then, open a terminal window and navigate to the directory containing these files. Finally, run the following command:

$ Python -m unittest

Output:

The output will typically consist of a series of dots or other symbols, with each symbol representing the execution of a single test case. A dot (.) indicates that the test case passed, while an “F” indicates that the test case failed. If all of the test cases pass, you should see a message indicating that all tests have been run and the total number of tests that were run.

....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

If any of the test cases fail, the output will include a detailed error message indicating what went wrong. Let’s take an example where the test case failed, for that, we have modified the math_functions.py file so that it will return a string which will cause an error as an integer value is expected.

Python3




# Program with error in one function
def addition(a, b):
    return "error_causing_format"
 
def subtraction(a, b):
    return a - b
 
def multiplication(a, b):
    return a * b
 
def division(a, b):
    return a / b


Now if we run the “test_math_functions.py” file the same as before then we will get the following error message:

F...
======================================================================
FAIL: test_addition (test_math_functions.TestMathFunctions.test_addition)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\siddh\OneDrive\Desktop\GFG\test_math_functions.py", line 7, in test_addition
    self.assertEqual(result, 4)
AssertionError: 'error' != 4

----------------------------------------------------------------------
Ran 4 tests in 0.002s

FAILED (failures=1)

In the above case, the first test case failed, and hence the output shows FAILED status.

Here are a few additional points to consider when organizing your tests using unittest:

  • It is generally a good idea to keep your test files separate from your main code files. This helps to keep your codebase clean and organized and makes it easier to run your tests without having to worry about conflicts with your main code.
  • You can use the “setUp()” and “tearDown()” methods of the unittest. TestCase class to perform any necessary setup or cleanup tasks before or after each test case is run. This can be helpful for creating test data or cleaning up after tests.
  • You can use the “skipTest()” method of the unittest. TestCase class to skip a particular test case if it is not relevant or if the necessary dependencies are not available.
  • You can use the “-v” flag when running your tests to enable verbose output, which will display the names of each test case as it is run. This can be helpful for debugging or for getting a better understanding of the test suite.
  • You can use the “-s” flag when running your tests to specify the directory containing your test files. This can be helpful if your test files are not located in the default location (e.g., “tests”).
  • You can use the “-p” flag when running your tests to specify a pattern for selecting which test files to run. This can be helpful if you want to run only a subset of your test suite.


Last Updated : 01 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads