Closed baileythegreen closed 1 year ago
I believe that working within the pytest
framework provides additional information about assert
statements to that reported in plain Python. See, for instance, this documentation.
Briefly, consider two files:
plain.py
# plain Python
a = 5
b = 4
assert a == b
pytest_python.py
# Python using Pytest
def test_function():
a = 5
b = 4
assert a == b
Now, running the first script with Python gives the normal AssertionError
% python plain.py
Traceback (most recent call last):
File "/Users/lpritc/Desktop/plain.py", line 6, in <module>
assert a == b
AssertionError
but with pytest
:
% pytest plain.py
================================================= test session starts =================================================
platform darwin -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/lpritc/Desktop
plugins: anyio-3.5.0
collected 0 items / 1 error
======================================================= ERRORS ========================================================
______________________________________________ ERROR collecting plain.py ______________________________________________
plain.py:6: in <module>
assert a == b
E assert 5 == 4
=============================================== short test summary info ===============================================
ERROR plain.py - assert 5 == 4
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================== 1 error in 0.19s ===================================================
I hope you would agree that, even with the bare assert
statement, the pytest
framework gives us adequate information to diagnose the issue, and arguably in a more elgant and readable way.
The second file illustrates the idiomatic way we would name this test for pytest
, rather than using bare Python, to give:
% pytest pytest_python.py
================================================= test session starts =================================================
platform darwin -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/lpritc/Desktop
plugins: anyio-3.5.0
collected 1 item
pytest_python.py F [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_function ____________________________________________________
def test_function():
a = 5
b = 4
> assert a == b
E assert 5 == 4
pytest_python.py:6: AssertionError
=============================================== short test summary info ===============================================
FAILED pytest_python.py::test_function - assert 5 == 4
================================================== 1 failed in 0.13s ==================================================
As we are using the pytest
framework for testing on this project, I think it is simpler not to make additional imports from unittest
at all, and in particular not to make a dummy object using unittest.TestCase("__init__")
in order to use its methods. This looks to me to be a bit of a hybrid of the two frameworks that doesn't really bring the advantages of either. If we were were using the unittest
framework (which, incidentally, we moved away from to adopt pytest
) each test case would be defined as a subclass of unittest.TestCase
and would automatically get these methods, e.g.
# Python with unittest
import unittest
class SimpleTest(unittest.TestCase):
def test(self):
a = 5
b = 4
self.assertEqual(a, b)
if __name__ == "__main__":
unittest.main()
which would then produce:
% python unittest_python.py
F
======================================================================
FAIL: test (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/lpritc/Desktop/unittest_python.py", line 9, in test
self.assertEqual(a, b)
AssertionError: 5 != 4
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
But this object-based approach isn't necessary with pytest
, or consistent with its style.
My view is that we should be testing using idiomatic pytest
wherever possible, and that the introduction of unittest
assertion methods isn't necessary.
This is just a general suggestion that for future development the assertion methods be considered as an alternative to plain
assert
; they may make it easier to understand why tests fail.An extremely simple example of the difference between the two is shown here:
With
assert
:and:
and with assertion methods:
and:
When it is not clear what the values are, the additional information may prove useful.