In this section, we will discuss two frameworks for writing and running unit tests. The first one, unittest, is available in the standard library of Python, while the second one, pytest, has to be installed externally via pip.
- unittest: https://docs.python.org/3/library/unittest.html
- pytest: https://docs.pytest.org/en/latest/
When it comes to covering testing scenarios for our code, unittest alone will most likely suffice, since it has plenty of helpers. However, for more complex systems on which we have multiple dependencies, connections to external systems, and probably the need to patch objects, and define fixtures parameterize test cases, then pytest looks like a more complete option.
We will use a small program as an example to show you how could it be tested using both options which in the end will help us to get a better picture of how the two of them compare.
The example demonstrating testing tools is a simplified version of a version control tool that supports code reviews in merge requests. We will start with the following criteria:
- A merge request is rejected if at least one person disagrees with the changes
- If nobody has disagreed, and the merge request is good for at least two other developers, it's approved
- In any other case, its status is pending
And here is what the code might look like:
from enum import Enum
class MergeRequestStatus(Enum):
APPROVED = "approved"
REJECTED = "rejected"
PENDING = "pending"
class MergeRequest:
def __init__(self):
self._context = {
"upvotes": set(),
"downvotes": set(),
}
@property
def status(self):
if self._context["downvotes"]:
return MergeRequestStatus.REJECTED
elif len(self._context["upvotes"]) >= 2:
return MergeRequestStatus.APPROVED
return MergeRequestStatus.PENDING
def upvote(self, by_user):
self._context["downvotes"].discard(by_user)
self._context["upvotes"].add(by_user)
def downvote(self, by_user):
self._context["upvotes"].discard(by_user)
self._context["downvotes"].add(by_user)