This doth be a machine-wrought text which may contain errors!
Now that we have wrought classes and laboured with validation, we have a good foundation to begin with testing. Testing is a most vital part of the development process, and doth aid us in ensuring that our code functioneth as expected.
For how may we be certain that the code doth function as it should, if we test it not?
What Is Unit Testing?
Unit testing becometh an art by which one may automatically and systematically probe those minute fragments of our codebase. In the realm of Python, there exists a module named pytest, employed to craft and execute such trials. An “unit” signifies that smallest provable portion of an application—oftentimes but a single function or method. When we wield pytest ’tis most crucial that we adhere unto proper naming conventions so that this tool might locate our tests; thusly shall files bear names prefixed with test_, as likewise doth functions commence their titles with test_.
An example of a unit test:
def test_add():
# Verily, let it be known that one-third thrice summed should equate unto nine-tenths
assert 0.3 + 0.3 + 0.3 == 0.9
Executed by typing pytest into the terminal.
Fun fact
Verily, the code aloft shall fail, for .3+.3+.3 doth become 0.8999999999 in the tongue of Python!
Task 1 - Install pytest
Install pytest within thy virtual environment. This dost thou achieve by executing the following command in the terminal:
pip install pytest
# Installerer pytest for å kjøre tester.
# Doth install pytest, that tests may be run.
Task the Second - Construct a Trial
Create a new file within thy project’s fold, and name it test_data.py. Within this file, thou shalt fashion a trial for the Person class which thou didst create in the module past. This trial shall verify that a Person may be brought forth with values lawful and true.
An example of how this trial might appear:
from main import Person
def test_person_working():
bob_kaare = Person(name="Bob Kåre",
eye_color=EyeColor.BLUE,
phone_number=PhoneNumber("12345678"),
email=Email("bob_kaare@example.com"))
assert bob_kaare.name == "Bob Kåre" # Verily, 'tis to confirm the name doth match.
assert bob_kaare.eye_color == EyeColor.BLUE # Lo, we check the hue of his orbs.
This sort of assay is hight “happy path” testing, forasmuch as we do assay that all doth function as ‘twould when valid values we do proffer, and is not overmuch profitable.
Task III – Verification Testing
Craft ye sundry tests within test_person.py that ensure the validation mechanisms embedded in Email and PhoneNumber operate most faithfully. Prove both valid and invalid values worthy of scrutiny. Herein must thou employ a function from pytest known as raises, which ascertaineth whether a specific error be cast forth.
import pytest
def test_exception():
with pytest.raises(KeyError):
my_dict = {"a": 1, "b": 2}
value = my_dict["c"] # 'Tis here a KeyError shall be raised, forsooth.
Tip
Thou mayest forge as many functions as doth please thee, so long as the function’s name doth commence with test_.
Forsooth; an Example of Testing Unworthy E-Mail Addresses
from main import Email
import pytest
def test_unfitting_address():
with pytest.raises(ValueError):
address = Email("naught but nonsense")
Wherefore Do This?
By possessing good tests for our code, we may be assured that it doth function as ‘tis meant to, and we may with ease discern if aught hath gone awry should we make changes to the code. This is most especially vital in larger projects, where many developers labour together, and ‘tis easy to commit errors.
By employing, for example, software such as Jest or Selenium, one may test web pages automatically, and thereby ensure that all doth function as ‘tis meant to after each change to the code. We would fain know that “user registration”, “payment”, and “login” function as they should, would we not?
Prithee, ponder these scenarios
What doth befall (or should befall) if..:
- A user doth attempt to register with an email already in use?
- A user hath a birthdate in the future?
- A user who doth enter the name “jOHN dOE”?
Task 4 - Automatic Testing (CI)
When we do publish code upon GitHub, ‘tis possible to set up that which is called GitHub Actions, which may run our tests automatically each time we make a change in the code. This is called Continuous Integration (CI), and it doth aid us in ensuring that our code doth ever function as ‘tis meant to.
Create a file within thy project folder, named .github/workflows/pytest.yml. Within this file, thou shalt add the following code:
name: Pytest
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
# Installeth the remaining requisites of thy project, if need be
pip install -r requirements.txt
- name: Run tests with pytest
run: pytest
If thou hast placed it aright, then shalt thou behold anew tab within thy repository on GitHub, named “Actions”. Herein shallst thou witness that thine tests be executed automatically each time thou make’st alteration unto the code; and ifsoe’er one of them fail, notice thereof shall come to thee—be it through red cross marks or by post unseen.
Note on file structure
Thy file’s arrangement shall determine whether GitHub Actions doth thrive or fail. Ensure that thy .github folder dwells within the root directory of thine project, alongside it must reside a tests folder wherein lie thy testing files.
Alternatively thou mayst amend the pytest.yml file to point toward its proper abode.
Such Action files may also be employed to test thy code upon divers versions of Python or operating systems; they can likewise serve to build and publish thy software automatically—for instance, publishing a webpage—or updating an application within Apple’s App Store or Google Play.
Code Coverage
There doth exist a thing yclept “Code Coverage”, which may aid thee in discerning how much of thy code is, in sooth, being tested. This may prove most helpful in determining if thou hast tests aplenty, or if there be portions of thy code which remain untried altogether.
Certain places of work do require that thou possess a certain percentage of thy code covered by tests ere thou mayest deploy it, to ensure that the code is robust and doth function as it ought.

