@@ -25,15 +25,10 @@ Automatic testing verifies code is still working.
2525
2626## Testing workflow
2727
28- ``` {mermaid}
29- flowchart TD
30- A[Prepare inputs]
31- B[Describe expected output]
32- C[Obtain actual output]
33- D[Compare actual and\n expected output]
34-
35- A --> B --> C --> D
36- ```
28+ 1 . Prepare inputs
29+ 2 . Describe expected output
30+ 3 . Obtain actual output
31+ 4 . Compare actual and expected output
3732
3833
3934## Unit testing
@@ -87,28 +82,16 @@ flowchart TD
8782
8883## Example
8984
90- 1 . get a timeseries of water levels
91- 2 . find the maxiumum water level each year
92- 3 . create a summary report for the subset of data
93-
94- ---
95-
96- 1 . get a timeseries of water levels
97-
98- ``` python
99- def test_get_water_level_includes_start_and_end ():
100- wl = get_water_level(time = " 2019-01-01" , location = " Aarhus" )
101-
102- assert len (wl) == 25
103- ```
85+ 1 . find the maximum water level each year
86+ 2 . create a summary report for the subset of data
10487
10588---
10689
107- 2 . find the maxiumum water level each year
90+ 1 . find the maximum water level each year
10891
10992``` python
11093def test_get_max_water_level ():
111- ts = TimeSeries([1.0 , .., 3.0 ], start = " 2019-01-01" )
94+ ts = TimeSeries([1.0 , 2.0 , . .. , 3.0 ], start = " 2019-01-01" )
11295 max_wls = get_max_water_level(ts, freq = " Y" )
11396
11497 assert len (max_wls) == 1
@@ -117,15 +100,15 @@ def test_get_max_water_level():
117100
118101---
119102
120- 3 . create a summary report for the subset of data
103+ 2 . create a summary report for the subset of data
121104
122105``` python
123106def test_summary_report ():
124107 max_wls = [1.0 , 2.0 , 3.0 ]
125- report = summary_report(max_wls)
108+ report = summary_report(max_wls, station = " Station A " )
126109
127- assert report.title == " Summary report"
128- assert report.text == " The maximum water level in 2021 was 3.0 m"
110+ assert report.title == " Summary report - Station A "
111+ assert report.text == " The maximum water level during the year was 3.0 m"
129112```
130113
131114## Integration testing
@@ -142,6 +125,25 @@ def test_integration():
142125```
143126
144127
128+ ## Regression testing
129+
130+ ::: {.incremental}
131+
132+ * Not a distinct test type, but a process
133+
134+ * A regression = when code changes break previously working behavior
135+
136+ * Regression testing = rerunning your existing test suite after each change
137+
138+ * Test suite grows over time:
139+
140+ - Unit/integration tests
141+
142+ - Tests added for fixed bugs
143+
144+ * Goal: ensure new changes don’t reintroduce old bugs or unexpected behavior
145+ :::
146+
145147## Testing in VS Code
146148
147149![ ] ( images/vs_code_test.png )
@@ -165,7 +167,7 @@ def test_integration():
165167``` python
166168@pytest.fixture
167169def water_level ():
168- return TimeSeries([1.0 , .., 3.0 ], start = " 2019-01-01" )
170+ return TimeSeries([1.0 , ... , 3.0 ], start = " 2019-01-01" )
169171
170172def test_get_max_water_level (water_level ):
171173 max_wls = get_max_water_level(water_level, freq = " Y" )
@@ -180,7 +182,7 @@ def test_get_max_water_level(water_level):
180182::: {.incremental}
181183
182184* A measure of how much of your code is tested
183- * A good test suite should cover all the code
185+ * Aim for high coverage, but focus on meaningful tests
184186* Install ` pytest-cov `
185187* Run tests with coverage report
186188 - ` pytest --cov=myproj `
@@ -225,7 +227,7 @@ TOTAL 353 20 94%
225227
226228:::
227229
228- ## Tests act as specification
230+ ## Tests document expected behavior
229231
230232``` python
231233def test_operable_period_can_be_missing ():
@@ -308,7 +310,7 @@ Readability counts.
308310 + ` KeyError `
309311 + ` ValueError `
310312 + ` FileNotFoundError `
311- * You can also create your own custom exceptions, e.g. ` ModelInitialistionError ` , ` MissingLicenseError ` ?
313+ * You can also create your own custom exceptions, e.g. ` ModelInitError ` , ` MissingLicenseError ` ?
312314
313315:::
314316
@@ -358,9 +360,9 @@ The same can be done with warnings.
358360
359361## Linting
360362
361- A way to check your code for common errors and style issues.
363+ A quick way to check your code for common errors and style issues.
362364
363- [ ` ruff ` ] ( https://docs.astral.sh/ruff/ ) is a new tool for linting Python code.
365+ [ ` ruff ` ] ( https://docs.astral.sh/ruff/ ) is a recent tool for linting Python code.
364366
365367* syntax errors
366368* unused imports
@@ -409,7 +411,7 @@ Found 3 errors.
409411* Formatting code for readability and maintainability is essential.
410412* ` ruff ` can be used for code formatting (in addition to linting).
411413* ` ruff ` is a faster replacement of ` black ` , a previously commonly used code formatter.
412- * It enforces its own rules for formatting, which are only minorly configurable .
414+ * It enforces its own rules for formatting, with limited configurability .
413415* Having a unified style makes code changes easier to understand and collaborate on.
414416
415417:::
@@ -461,7 +463,7 @@ Visual Studio Code can be configured to run `ruff format` automatically when sav
461463``` python
462464import numpy as np
463465
464- def top_neighbors (points , radius = " 0.1" ):
466+ def top_neighbors (points , radius = 0.1 ):
465467 """ Don't use this function, it's only purpose is to be profiled."""
466468 n = len (points)
467469 idx = np.array([int (x) for x in str .split(" 0 " * n)])
0 commit comments