Let’s introduce one more useful tool as part of this example, the Hamcrest assertion library. Hamcrest is a library of unit test assertions that is available for multiple programming languages, including both Java and Python. Hamcrest makes it easy to write very advanced assertions in a way that is both readable and flexible. In fact, most of the autograders in prior CC courses use Hamcrest as the primary assertion library to make them easy to develop. Let’s explore what it takes to add Hamcrest to our project.
To make Hamcrest available, we simply have to add an entry for
pyhamcrest to our
requirements.txt file. Once we update that file, it will look like this:
coverage flake8 flake8-docstrings flake8-html lxml mypy pdoc3 pep8-naming pyhamcrest pytest pytest-html tox
Then we can install it using this command from within the
pip3 install -r requirements.txt
That’s all there is to it! We now can use Hamcrest in our unit tests
Unit Test with Hamcrest
Now, let’s build a unit test that uses Hamcrest. So, in the
test/hello directory, create a new file called
test_HelloWorldHamcrest.py and paste the following code in that file:
"""Test Class for HelloWorld using Hamcrest. Author: Russell Feldhausen email@example.com Version: 0.1 """ from hamcrest.core.assert_that import assert_that from hamcrest.core.core.is_ import is_ from pytest import CaptureFixture from _pytest.capture import CaptureResult from typing import Any from src.hello.HelloWorld import HelloWorld class TestHelloWorldHamcrest(): """Test Class for `src.hello.HelloWorld`.""" def test_hello_world(self, capsys: CaptureFixture[Any]) -> None: """Test Method for `src.hello.HelloWorld.main`. This will test the main method with no arguments. Args: capsys: PyUnit fixture to capture output. """ HelloWorld.main(["HelloWorld"]) captured: CaptureResult[Any] = capsys.readouterr() assert_that(captured.out, is_("Hello World\n"), "Unexpected Output") def test_hello_world_arg(self, capsys: CaptureFixture[Any]) -> None: """Test Method for `src.hello.HelloWorld.main`. This will test the main method with 1 argument. Args: capsys: PyUnit fixture to capture output. """ HelloWorld.main(["HelloWorld", "CC 410"]) captured: CaptureResult[Any] = capsys.readouterr() assert_that(captured.out, is_("Hello CC 410\n"), "Unexpected Output")
The code is nearly identical to the other unit test class, but with two major changes:
- There are a couple of new import statements at the top to include the
is_methods from Hamcrest.
- Instead of using
assertthe last line of each unit test uses
assert_that. The order of the arguments and the basic idea is pretty much the same. Also, note the use of the
is_method, which is simply stating that it should be equal. That method name includes an underscore to differentiate it from the
iskeyword in Python.
Of course, a simple test case such as this doesn’t show the power of using Hamcrest instead of the built-in assertions in pyunit. If you want to know more about Hamcrest, feel free to check out the Hamcrest documentation . We’ll explore more about using Hamcrest in our unit tests later in this course.
Now that we’ve created a new unit test class, let’s go ahead and run it. Thankfully, we don’t have to do anything else - pyunit will automatically find the new unit test class and execute it along with all the others. So, in a Linux terminal in the
python directory, run the following command to execute those tests, along with the rest of our commands:
When the tests are complete, we can open the report and we should now see that there are 4 tests that executed successfully:
While we’re at it, since we added new code and unit tests we should also check to make sure that our code coverage is still good:
As long as the tox command executes, we also know that the code passed all of our Flake8 style checks, and updated the documentation using pdoc3 as well.
If you run into any errors on any of those commands, now is a good time to get them resolved before moving on! This is the last step before we submit our code!
Click the link below to jump to the end where we submit our code.