Unit Testin' and Validatin',

Skip to content

This here’s a machine-translated text that might contain some errors!

Now that we’ve built classes and worked with validation, we got a good foundation for startin’ with testin’. Testin’ is a mighty important part of the development process, and it helps us make sure our code works like we expect it to.

‘Cause how can we be sure the code works right if we don’t test it?

What is Unit Testing?

Unit Testing is a method for automatically and systematically testin’ small parts of our code. In Python, we use a module called pytest to write and run tests. A “unit” is the smallest testable part of an application, often a single function or method. When we’re usin’ pytest, it’s important that we follow the right namin’ conventions for pytest to be able to find our tests, like namin’ test files with test_ in front, and test functions with test_ in front.

Example of a unit test:

def test_add():
    # Sjekker om addisjon fungerer som forventet.
    # Checkin' if addin' works like it oughta.
    assert 0.3 + 0.3 + 0.3 == 0.9

Run by typin’ pytest in the terminal.

Fun fact

The code above will fail, ‘cause .3+.3+.3 becomes 0.8999999999 in Python!

Easy Task 1 - Install pytest

Install pytest in yer virtual environment. Ye do this by runnin’ the followin’ command in the terminal:

pip install pytest
# Installer pytest - et rammeverk for å skrive og kjøre tester.
# Installs pytest - a framework for writin' and runnin' tests.

Easy Task 2 - Build a Test

Create a new file in yer project folder called test_data.py. In this here file, ya gotta build a test for the Person class ya made in the previous module. This test needs to check if a Person can be created with valid values.

Here’s an example of what the test might look like:

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" # Sjekker at navnet er riktig.
    assert bob_kaare.eye_color == EyeColor.BLUE # Sjekker at øyenfargen er riktig.

This here kinda testin’ is called “happy path” testin’, ‘cause we’re checkin’ if ever’thin’ works like it should when we give it good, valid values, and it ain’t all that useful, ya see.

Medium Task 3 - Test Validation

Build more tests in test_person.py that check that the validation in Email and PhoneNumber works as it should. Test both valid and invalid values. Here ya gotta use a function in pytest called raises, which checks that a specific error is thrown.

import pytest

def test_exception():
    with pytest.raises(KeyError):
        my_dict = {"a": 1, "b": 2}
        value = my_dict["c"]  # This here'll "raise" a KeyError

Tip

You can make as many functions as ya please, as long as the function name starts 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 Go To All This Trouble?

By havin’ good tests for our code, we can be sure it works like it’s supposed to, and we can easily figure out if somethin’s gone wrong if we make changes to the code. This here’s especially important in bigger projects, where a lot of developers are workin’ together, and it’s easy to make mistakes.

By usin’ software like Jest or Selenium, for example, a fella can test websites automatically, and thus make sure everything works as it should after every change to the code. We sure do wanna know that “user registration”, “payment”, and “login” are workin’ right, don’t we?

Consider the following scenarios

What happens (or should happen) if..:

  • A user tries to register with an email that is already in use?
  • A user has a future date of birth?
  • A user enters the name “jOHN dOE”?

A software tester walks into a bar...

Hard Task 4 - Automatic Testin’ (CI)

When we publish code on GitHub, we can set up somethin’ called GitHub Actions that can run our tests automatically every time we make a change to the code. This here’s called Continuous Integration (CI), and it helps us make sure our code always works like it oughta.

Create a file in yer project folder called .github/workflows/pytest.yml. In this file, ya gotta 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
        pip install -r requirements.txt
    - name: Run tests with pytest
      run: pytest

Now, if ya done set it up right, ya should see a new tab in yer GitHub repo called “Actions”. Right there ya can watch yer tests run automatic every time ya make a change to the code, and ya’ll get a holler if any o’ them tests fail (red X and by email).

Merknad om filstruktur

Your file structure’ll decide if GitHub Actions works or not. Make sure the .github folder’s in the root of yer project, and the same goes for a tests folder where yer test files are.

You can also change the pytest.yml file to point to the right folder.

Them 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 and publish yer software automatically, fer example, publishin’ a website, or updatin’ an app in the App Store or Google Play.

Code Coverage

There’s also somethin’ called “Code Coverage”, which can help ya see how much of yer code is actually bein’ tested. This can be handy for figurin’ out if ya got enough tests, or if there’s parts of yer code that ain’t bein’ tested at all.

Some workplaces require ya to have a certain percentage of yer code covered by tests before ya can deploy it, to make sure the code is sturdy and works like it should.

Unit Test Meme