Skip to content

Commit be695f9

Browse files
committed
feat(tests): work-in-progress writing page
1 parent fe2ad07 commit be695f9

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

pages/verification_validation/tests.qmd

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
title: ❌ Tests
33
---
44

5+
{{< include ../../scripts/_reticulate-setup.md >}}
6+
57
:::: {.pale-blue}
68

79
**Learning objectives:**
@@ -18,7 +20,28 @@ TODO
1820

1921
**Required packages:**
2022

21-
TODO
23+
These should be available from environment setup in the "Test yourself" section of [Environments](../setup/environment.qmd).
24+
25+
::: {.python-content}
26+
27+
```{python}
28+
import numpy as np
29+
import pandas as pd
30+
import simpy
31+
from sim_tools.distributions import Exponential
32+
import pytest
33+
```
34+
35+
:::
36+
37+
::: {.r-content}
38+
39+
```{r}
40+
#| output: false
41+
library(simmer)
42+
```
43+
44+
:::
2245

2346
::::
2447

@@ -28,6 +51,120 @@ TODO
2851
3. github repo > settings > secrets and variables > actions > new token and copy in the info
2952
4. run workflow -->
3053

54+
<br>
55+
56+
Testing is the process of evaluating a model to ensure it works as expected, gives reliable results, and can handle different conditions. By **systematically checking for errors, inconsistencies, or unexpected behaviors**, testing helps improve the quality of a model, catch errors and prevent future issues.
57+
58+
When you create a model, you will naturally carry out tests, with simple manual checks where you observe outputs and ensure they look right. These checks can be formalised and **automated** so that you can run them after any changes, and catch any issues that arise.
59+
60+
## Introduction to writing and running tests
61+
62+
<div class="h3-tight"></div>
63+
64+
:::: {.python-content}
65+
66+
### Writing a basic test
67+
68+
A popular framework for testing in python is **pytest**.
69+
70+
Each test in pytest is a function that contains an assertion statement to check a condition (e.g., `number > 0`). If the condition fails, pytest will return an error message (e.g. "The number should be positive").
71+
72+
Test are typically stored in a folder called `tests/`, and filenames start with the prefix `test_`. This naming convention allows pytest to automatically discover and run all the tests in the folder.
73+
74+
Here's an example of a simple test using pytest:
75+
76+
```{python}
77+
def test_positive():
78+
"""
79+
Confirm that the number is positive.
80+
"""
81+
number = 5
82+
assert number > 0, "The number should be positive"
83+
```
84+
85+
### Running tests
86+
87+
Tests are typically run from the terminal. Commands include:
88+
89+
* `pytest` - runs all tests.
90+
* `pytest tests/filename.py` - runs tests from a specific file.
91+
92+
When you run a test, you'll see an output like this in the terminal:
93+
94+
::: {.callout-note icon=false title="Test output:"}
95+
96+
```{python}
97+
#| echo: false
98+
pytest.main(["tests_resources/test_example_simple.py"])
99+
```
100+
101+
:::
102+
103+
### Parametrise
104+
105+
We can execute the same test on different parameters using `pytest.mark.parametrize`.
106+
107+
Here's an example:
108+
109+
```{python}
110+
@pytest.mark.parametrize("number", [1, 2, 3, -1])
111+
def test_positive_param(number):
112+
"""
113+
Confirm that the number is positive.
114+
115+
Arguments:
116+
number (float):
117+
Number to check.
118+
"""
119+
assert number > 0, f"The number {number} is not positive."
120+
```
121+
122+
In this example, we're testing the same logic with four different values: `1`, `2`, `3`, and `-1`. The last value, `-1`, will cause the test to fail. The error message includes the failed value for easy debugging.
123+
124+
:::{.callout-note icon=false title="Test output:"}
125+
126+
```{python}
127+
#| echo: false
128+
pytest.main(["tests_resources/test_example_param.py"])
129+
```
130+
131+
:::
132+
133+
::::
134+
135+
::: {.r-content}
136+
137+
:::
138+
139+
## Testing the model
140+
141+
There are many different ways of categorising tests. We will focus on three types:
142+
143+
* **Functional testing**
144+
* **Unit testing**
145+
* **Back testing**
146+
147+
### Functional tests
148+
149+
Functional tests verify that the system or components perform their intended functionality.
150+
151+
For example, we expect that the mean wait time for a doctor should decrease if:
152+
153+
* The number of doctors increases.
154+
* The patient inter-arrival time increases (so there are fewer arrivals).
155+
* The length of the doctor consultation decreases.
156+
157+
::: {.python-content}
158+
159+
```{python}
160+
```
161+
162+
:::
163+
164+
::: {.r-content}
165+
166+
:::
167+
31168
## Explore the example models
32169

33170
<div class="h3-tight"></div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pytest
2+
3+
4+
@pytest.mark.parametrize("number", [1, 2, 3, -1])
5+
def test_positive_param(number):
6+
"""
7+
Confirm that the number is positive.
8+
9+
Arguments:
10+
number (float):
11+
Number to check.
12+
"""
13+
assert number > 0, f"The number {number} is not positive."
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def test_positive():
2+
"""
3+
Confirm that the number is positive.
4+
"""
5+
number = 5
6+
assert number > 0, "The number should be positive"

0 commit comments

Comments
 (0)