Avast ye, this be a machine-translated text an’ may contain errors, aye!
Now that we’ve crafted our classes and toiled with validation, we have a fine foundation to begin with testing. Testing be a vital part o’ the development process, and it helps us ensure our code functions as expected.
For how can we be certain the code be workin’ as it should, if we don’t test it, aye?
What Be Unit Testin’, Aye?
Unit Testin’ be a method for automatically and systematically testin’ small parts o’ our code. In Python, we use a module called pytest to write and run tests. A “unit” be the smallest testable part o’ an application, often a single function or method. When we be usin’ pytest, ‘tis be important that we follow the proper namin’ conventions for pytest to be able to find our tests, such as namin’ test files with test_ afore, and test functions with test_ afore.
Example o’ a unit test:
def test_add():
# Sjekker om addisjon fungerer som forventet.
# Aye, checkin' if addin' be workin' as expected.
assert 0.3 + 0.3 + 0.3 == 0.9
Be run by writin’ pytest in the terminal, aye.
Fun fact
The code above will fail, for .3+.3+.3 becomes 0.8999999999 in Python!
Task 1 - Install pytest
Install pytest in yer virtual environment, aye. Ye do this by runnin’ the followin’ command in the terminal:
pip install pytest
# Installerer pytest for testing. --> Ahoy, installin' pytest for testin', ye scurvy dogs!
Task 2 - Craft a Test
Craft a new file within yer project holdin’ the name test_data.py. Within this file, ye shall forge a test for the Person class ye built in the previous module. This test be checkin’ that a Person can be created with valid values.
Example o’ how the test might look:
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"))
# Aye, checkin' if the name be correct, savvy?
assert bob_kaare.name == "Bob Kåre"
# Verifying the eye color, arrr!
assert bob_kaare.eye_color == EyeColor.BLUE
This here type o’ testin’ be called “happy path” testin’, see? ‘Tis ‘cause we be testin’ if all be workin’ as it should when givin’ valid values, an’ it ain’t much use, savvy?
Task 3 - Test Validation
Craft ye more tests in test_person.py to ensure the validation within Email and PhoneNumber be workin’ as it should. Test both valid and invalid values, aye. Here ye must use a function in pytest called raises, which checks that a certain error be cast.
import pytest
def test_exception():
with pytest.raises(KeyError):
my_dict = {"a": 1, "b": 2}
value = my_dict["c"] # Aye, this'll be raisin' a KeyError, savvy?
Tip
Ye can craft as many functions as ye please, so long as the function’s name begins with test_.
Løsning: Eksempel på en test for ugyldig e-post
from main import Email
import pytest
def test_invalid_email():
with pytest.raises(ValueError):
email = Email("not-an-email")
Why be doin’ this, aye?
By havin’ good tests for our code, we can be sure it be workin’ as it should, and we can easily find out if somethin’ has gone wrong if we make changes to the code. This be especially important in larger projects, where many developers be workin’ together, and it be easy to make mistakes.
By usin’ software like Jest or Selenium, for example, one can test websites automatically, and thus ensure that everything be workin’ as it should after each change to the code. We’d like to know that “user registration”, “payment”, and “login” be workin’ as they should, wouldn’t we?
Ponder these here scenarios
What happens (or should happen) if..:
- A user tries to sign up with an email that be already in use?
- A user has a birthdate in the future?
- A user who enters the name “jOHN dOE”?
Task 4 - Automatic Testin’ (CI)
When we hoist the colors on GitHub, we can set up somethin’ called GitHub Actions that can run our tests automatically each time we make a change to the code. This be called Continuous Integration (CI), and it helps us ensure our code always works as it should.
Create a file in yer project folder called .github/workflows/pytest.yml. In this file, ye shall add the followin’ 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
# Install any other dependencies yer project needs, aye!
pip install -r requirements.txt
- name: Run tests with pytest
run: pytest
Aye, if ye’ve set it up right, ye should now be seein’ a new tab in yer GitHub repo called “Actions”. There ye’ll be able to see yer tests be runnin’ automatically each time ye make a change to the code, an’ ye’ll be notified if any o’ the tests fail (a red cross an’ by email).
Merknad om filstruktur
Yer file structure be the key to whether GitHub Actions sails smooth or runs aground! Make sure the .github folder be lyin’ in the root o’ yer project, and the same goes for a tests folder where yer test files be kept.
Ye can always tinker with the pytest.yml file to point to the right folder, aye.
Such Actions files can also be used to test yer code on multiple versions o’ Python or operatin’ systems, they can also be used to build an’ publish yer software automatically, fer example, publishin’ a webpage, or updatin’ an app in the App Store or Google Play.
Code Coverage
There be also a thing called “Code Coverage”, which can help ye see how much o’ yer code be actually tested. This can be useful for findin’ out if ye have enough tests, or if there be parts o’ yer code that ain’t tested at all.
Some workplaces require ye to have a certain percentage o’ yer code covered by tests afore ye can deploy it, to ensure the code be robust and works as it should.

