Or How to write unit tests in Python (inspired by Miguel Grinberg's blogpost) โ๏ธ
This repository contains notes and programs used to used Unit Tests in Python.
Involves evaluating individual components of a project to assure they behave as expected.
Involves evaluating two or more components of a project to make sure they work as a group - i.e., that they integrate well.
Requires the evaluation of features or functions of a project end-to-end to make sure it works as planned.
Role of Thumb: Test as much code as possible with unit tests, since they are easier to write and to run.
A test does two things:
- runs a small part of the application
- verifies (i.e., asserts) that resulting output of the code is correct
To execute such tests, one should save the test function as a Python file and start a test runner, that will find and alert any failed assertions.
Miguel uses a hybrid of both packages on his testing solutions so that is what will be seen here.
unittest
package- will be used to structure and organise the tests on a OOP-approach based on the
TestCase
.
- will be used to structure and organise the tests on a OOP-approach based on the
pytest
package- enhanced
assert
function that provides more verbose failure outputs - choice of test runner since fully supports the
TestCase
class fromunittests
.
- enhanced
To explain the theory, we will code the Fizz Buzz game
Check out the unfactored original code here. And the testable and factored commented version in here.
To run a test simply type
pytest
on terminal with the test.py file on the same folder as the function to be tested.
A auccessful test will look like this:
(fizz-buzz_env) lais@lais-xps:~/Documents/projects/fizzbuzz_unit-test$ pytest
==================================================================================================== test session starts =====================================================================================================
platform linux -- Python 3.8.5, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
rootdir: /home/lais/Documents/projects/fizzbuzz_unit-test
collected 1 item
test_fizzbuzz.py . [100%]
===================================================================================================== 1 passed in 0.04s ======================================================================================================
On the other hand, a failing test will look like this:
========================================================================================================== FAILURES ==========================================================================================================
___________________________________________________________________________________________________ TestFizzBuzz.test_fizz ___________________________________________________________________________________________________
self = <test_fizzbuzz.TestFizzBuzz testMethod=test_fizz>
def test_fizz(self):
for i in [3, 4, 6, 9, 18]:
print('testing', i)
> assert fizz_buzz_game(i) == "fizz"
E AssertionError: assert 4 == 'fizz'
E + where 4 = fizz_buzz_game(4)
test_fizzbuzz.py:10: AssertionError
---------------------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------------------
testing 3
testing 4
================================================================================================== short test summary info ===================================================================================================
FAILED test_fizzbuzz.py::TestFizzBuzz::test_fizz - AssertionError: assert 4 == 'fizz'
===================================================================================================== 1 failed in 0.05s ======================================================================================================
- Install the library with
conda install -c conda-forge pytest-cov
- Run
pytest --cov=fizzbuzz_2nditer
to show the percentage of coverage on your tests. - Run
pytest --cov=fizzbuzz_2nditer --cov-report=term-missing
to add the number of the lines of code that were not covered. - Run
pytest --cov=fizzbuzz_2nditer --cov-report=term-missing --cov-branch
treats lines with conditionals (if
) as needed double coverage to account for the two possible outcomes (truthy and falsey evals), named branch coverage.