Browse Courses

Test With Nose and Pytest

This document compares Python's unittest and Nose test runners, showing how to run tests, interpret reports, and use coverage tools for better code quality.

This document explains how to run Python unit tests using both unittest and Nose, highlights the differences in their reports, and demonstrates how Nose can improve test output and code coverage analysis.


Introduction

Automated testing is essential for reliable software. Python offers several tools for running unit tests, including the built-in unittest module and the third-party Nose framework. This module explores how to use both tools and interpret their test reports.


Lab Setup

  • The course 11-tdd-bdd is set up with a dedicated folder for Python tests. It is present in the content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab directory.
  • To run the tests, a virtual environment is created using python -m venv venv. It creates a directory named .venv with necessary packages
  • To activate the virtual environment, run source venv/bin/activate.
  • But the existing setup requires to first launch a dedicated profile so that existing node environment is kept separate. The source is a linux command to run a script in the current shell session, allowing you to use the virtual environment’s Python interpreter and installed packages.
  • For bash use conda-bash which is an alias to run a profile to isolate the environment.
 1~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
 2ag-sayyed@p-3660 [Node: v24.4.0] [Git: feat/tdd-bdd]
 3$ echo $SHELL
 4/bin/bash
 5
 6~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
 7ag-sayyed@p-3660 [Node: v24.4.0] [Git: feat/tdd-bdd]
 8$ which python
 9# No answer means python is not installed in the current shell
10# So we need to run the profile to activate the virtual environment
11~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
12ag-sayyed@p-3660 [Node: v24.4.0] [Git: feat/tdd-bdd]
13$ conda-bash
14Initializing conda, If this shell session is exited, Conda will no longer be available unless re-initialized. No need to deactivate conda manually.
15[Git: feat/tdd-bdd] [Python: 3.13.2] (base) ) ag-sayyed@p-3660:~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
16$ which python
17/home/ag-sayyed/miniconda3/bin/python
18[Git: feat/tdd-bdd] [Python: 3.13.2] (base) ) ag-sayyed@p-3660:~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
19[Git: feat/tdd-bdd] [Python: 3.13.2] (base) ) ag-sayyed@p-3660:~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
20# Activate the newly created virtual environment
21$ source .venv/bin/activate
22(.venv) [Git: feat/tdd-bdd] [Python: 3.13.2] (base) ) ag-sayyed@p-3660:~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
23$ which python
24/home/ag-sayyed/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab/.venv/bin/python
25# Now python is used from `.venv/bin/python` which is the virtual environment
26(.venv) [Git: feat/tdd-bdd] [Python: 3.13.2] (base) ) ag-sayyed@p-3660:~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
27# you are ready to run the test.
  • Similarly for a fish shell, use conda-fish.
 1~/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab
 2ag-sayyed@p-3660 [Node: v24.4.0] [Git: feat/tdd-bdd]
 3$ fish
 4Loading custom fish configuration...
 5Welcome to fish, the friendly interactive shell
 6Type help for instructions on how to use fish
 7> ~/D/p/h/g/c/d/i/1/course-lab on feat/tdd-bdd ⨯ conda-fish           16:13:21
 8in ~/.config/fish/conda-profile.fish
 9
10ag-sayyed@p-3660 ~/D/p/h/g/c/d/i/1/course-lab (feat/tdd-bdd)11↪ which python
12/home/ag-sayyed/miniconda3/bin/python
13# Now activate the virtual environment using the script ending with `.fish`
14ag-sayyed@p-3660 ~/D/p/h/g/c/d/i/1/course-lab (feat/tdd-bdd)15source .venv/bin/activate.fish
16(.venv)
17ag-sayyed@p-3660 ~/D/p/h/g/c/d/i/1/course-lab (feat/tdd-bdd)18↪ which python
19/home/ag-sayyed/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab/.venv/bin/python
20(.venv)
21ag-sayyed@p-3660 ~/D/p/h/g/c/d/i/1/course-lab (feat/tdd-bdd)22# Now you are in the right shell and can run the tests

Running Tests with Unittest

Unit tests are the foundation of software testing, focusing on individual components or functions. Python’s unittest module provides a framework for writing and running these tests.

  • The unittest module is Python’s built-in test framework. To run tests, you can use the command line:
  • The unittest module (also known as PyUnit) is Python’s default test runner. You can run all tests in a folder using the command line:
1python -m unittest discover
  • First cd into the exercise folder:
 1cd content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab/module-02/testing-with-nose/labs/01_running_tests_with_nose
 2# Then run the test
 3ag-sayyed@p-3660 ~/D/p/h/g/c/d/i/1/c/m/t/l/01_running_tests_with_nose (main) 4↪ python -m unittest                                          15:55:02
 5...........
 6----------------------------------------------------------------------
 7Ran 11 tests in 0.000s
 8
 9OK
10(.venv)
  • Each passing test is shown as a dot (.), and failures are shown as F.
  • The summary report includes the number of tests run and the total time taken.

While unittest is simple and effective, its reports may lack detail and visual cues.


Running Tests with Nose

Nose is a popular alternative to unittest, offering more detailed and colourful output. To run tests with Nose:

1nosetests
  • Nose can be extended with plugins, such as Pinocchio, to add color to test results.
  • Passing tests appear in green, failing tests in red.
  • Test descriptions are shown if docstrings are present in test cases.

You can configure Nose to use plugins and options via a configuration file, reducing the need to specify them on the command line each time.


Comparing Test Reports

FeatureunittestNose (with plugins)
Output StyleDots and lettersColorized, descriptive
Detail LevelBasicDetailed, with docstrings
Code Coverage SupportLimitedIntegrated with plugins
Missing Test LinesNot shownListed in coverage report

Nose provides a more informative and visually helpful report, making it easier to identify issues and improve code quality.


Code Coverage and Missing Tests

Nose can be configured to run code coverage analysis after tests complete. The coverage report shows:

  • The percentage of code executed by tests for each module.
  • A list of lines missing test coverage, helping you focus your testing efforts.

Maintaining high code coverage is important for ensuring that new and existing code is well-tested and trustworthy.


Running Test with Pytest

  • First install pytest in your virtual environment:
 1pip install pytest
 2↪ pip list                                                                                                                                                                     23:01:01
 3Package   Version
 4--------- -------
 5iniconfig 2.1.0
 6packaging 25.0
 7pip       25.1.1
 8pluggy    1.6.0
 9Pygments  2.19.2
10pytest    8.4.1
11(.venv)
  • Then run the tests using pytest:
 1pytest test_triangle.py                                                                                                                                                      23:04:05
 2================================================================================= test session starts =================================================================================
 3platform linux -- Python 3.13.2, pytest-8.4.1, pluggy-1.6.0
 4rootdir: /home/ag-sayyed/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab/module-02/testing-with-nose/labs/01_running_tests_with_nose
 5collected 11 items
 6
 7test_triangle.py ...........                                                                                                                                                    [100%]
 8
 9================================================================================= 11 passed in 0.01s ==================================================================================
10(.venv)
  • Pytest provides a clean and concise output, showing the number of tests passed and the time taken.

Fail Test Example

  • To demonstrate a failing test, you can modify the test_float_values function to include an incorrect assertion:
 1def test_float_values():
 2    """Test areas when values are floats"""
 3    assert pytest.approx(area_of_a_triangle(3.4556, 8.3567), rel=1e-8) == 14.43870626
 4    assert area_of_a_triangle(2.3, -1) == 6.555
 5 pytest test_triangle.py                                                                                                                                                      23:09:55
 6================================================================================= test session starts =================================================================================
 7platform linux -- Python 3.13.2, pytest-8.4.1, pluggy-1.6.0
 8rootdir: /home/ag-sayyed/Documents/projects/hbstack/ghafoors-blog/content/docs/ibm-devops-software-eng-pcert/11-tdd-bdd/course-lab/module-02/testing-with-nose/labs/01_running_tests_with_nose
 9collected 11 items
10
11test_triangle.py F..........                                                                                                                                                    [100%]
12
13====================================================================================== FAILURES =======================================================================================
14__________________________________________________________________________________ test_float_values __________________________________________________________________________________
15
16    def test_float_values():
17        """Test areas when values are floats"""
18        assert pytest.approx(area_of_a_triangle(3.4556, 8.3567), rel=1e-8) == 14.43870626
19>       assert area_of_a_triangle(2.3, -1) == 6.555
20               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
21
22test_triangle.py:7:
23_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
24
25base = 2.3, height = -1
26
27    def area_of_a_triangle(base: float, height: float) -> float:
28        """Calculates the area of a triangle"""
29
30        # Check if we have the correct parameter types
31        if type(base) not in [int, float]:
32            raise TypeError("Base must be a number")
33        if type(height) not in [int, float]:
34            raise TypeError("Height must be a number")
35
36        # Check if we have the correct parameter values
37        if base < 0:
38            raise ValueError("Base must be a positive number")
39        if height < 0:
40>           raise ValueError("Height must be a positive number")
41E           ValueError: Height must be a positive number
42
43triangle.py:14: ValueError
44=============================================================================== short test summary info ===============================================================================
45FAILED test_triangle.py::test_float_values - ValueError: Height must be a positive number
46============================================================================ 1 failed, 10 passed in 0.04s =============================================================================
47(.venv)

Conclusion

Both unittest and Nose can run Python unit tests effectively, but Nose offers more detailed and visually appealing reports, but it would only work with python3.10. Pytest is a modern alternative that combines the best features of both frameworks, making it a popular choice for new projects.


FAQs

The command python -m unittest discover runs all tests in the specified folder using unittest.

Nose provides more detailed, colorized output and can show test descriptions and code coverage reports.

Nose can generate a coverage report that lists lines of code not covered by any test, helping developers focus their testing efforts.

  1. unittest provides only dots and letters, while Nose can show colorized, descriptive output
  2. Both provide identical reports
  3. Nose cannot show code coverage
  4. unittest is always more detailed than Nose
(1) unittest provides basic output, while Nose offers colorized, descriptive reports and coverage integration.

You can identify which lines of code are not tested, allowing you to improve your test coverage and code reliability.

FeatureDescription
A. Colorized Output1. Shows which lines of code are not covered by tests
B. Coverage Report2. Highlights passing and failing tests visually
C. Test Descriptions3. Displays docstrings for each test in the output
A-2, B-1, C-3.

Nose can be configured to show which lines of code are missing test coverage.

True. Nose, with coverage plugins, can report missing test lines, helping developers improve code coverage.