Skip to content

Commit 9787ace

Browse files
Rework Chapter 5 intro and Python testing slides (#212)
* Rework learning goals of Chapter 5, and introduction to testing slides * Shorten learning goal for testing part Co-authored-by: Benjamin Uekermann <benjamin.uekermann@ipvs.uni-stuttgart.de> * Capital case in titles of slides * Rework Python testing demo and content slides * Update exercise * Minor tweaks to exercise * Reworking Python testing demo content based on a trial --------- Co-authored-by: Benjamin Uekermann <benjamin.uekermann@ipvs.uni-stuttgart.de>
1 parent 4bd9f2f commit 9787ace

File tree

8 files changed

+83
-72
lines changed

8 files changed

+83
-72
lines changed

05_testing_and_ci/examples/python_testing/operations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ def main():
5454
data = [5, 3, 14, 27, 4, 9]
5555

5656
maximum = find_max(data)
57-
print("Maximum = {}".format(maximum))
57+
print("Maximum of {} is {}".format(data, maximum))
5858

5959
mean = find_mean(data)
60-
print("Average = {}".format(mean))
60+
print("Average of {} is {}".format(data, mean))
6161

6262

6363
if __name__ == "__main__":

05_testing_and_ci/examples/python_testing/test_operations_unittests.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Tests for mathematical operations functions.
33
"""
44
from operations import find_max, find_mean
5+
import unittest
56
from unittest import TestCase
67
import csv
78

@@ -78,3 +79,7 @@ def test_regression_mean(self):
7879

7980
# Test
8081
self.assertAlmostEqual(actual_mean, reference_mean[0], 2)
82+
83+
if __name__ == "__main__":
84+
# Run the tests
85+
unittest.main()

05_testing_and_ci/examples/python_testing/tox.ini

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
requires = ["tox>=4"]
2+
env_list = ["testing"]
3+
4+
[env.testing]
5+
description = "Run pytest"
6+
deps = ["pytest>=8"]
7+
commands = [["pytest"]]

05_testing_and_ci/intro_slides.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ slideOptions:
2929

3030
## Learning Goals of the Chapter
3131

32-
- Justify the effort of developing testing infrastructure for simulation software
33-
- Discern the concepts of unit testing, integration testing and regression testing with the perspective of simulation software
34-
- Work with the Python testing frameworks `pytest` and `unittest`
32+
- Explain why developing tests is crucial.
33+
- Explain the concepts of unit testing, integration testing and regression testing with the perspective of simulation software.
34+
- Write tests using the Python libraries `pytest` and `unittest`.
35+
- Write tests in C++ using `Boost.Test`.
36+
- Explain the concepts of automation workflows in RSE.
37+
- Write automation workflows using GitHub Actions and GitLab CI.
3538

3639
---
3740

@@ -48,7 +51,7 @@ slideOptions:
4851
- Improve software reliability and reproducibility.
4952
- Make sure that changes (bugfixes, new features) do not affect other parts of software.
5053
- Generally all software is better off being tested regularly. Possible exceptions are very small codes with single users.
51-
- Ensure that a released version of a software actually works.
54+
- Ensure that a distributed/packaged software actually works.
5255

5356
---
5457

@@ -93,7 +96,7 @@ assert condition, "message"
9396
- A *unit* is a single function in one situation.
9497
- A situation is one amongst many possible variations of input parameters.
9598
- User creates the expected result manually.
96-
- Fixture is the set of inputs used to generate an actual result.
99+
- A fixture is a set of inputs used to generate an actual result.
97100
- Actual result is compared to the expected result, for e.g. using an assertion statement.
98101

99102
---
@@ -120,9 +123,9 @@ assert condition, "message"
120123

121124
## Test Coverage
122125

123-
- Coverage is the amount of code a test touches in one run.
126+
- Coverage is the amount of code a test runs through.
124127
- Aim for high test coverage.
125-
- There is a trade-off: high test coverage vs. effort in test development
128+
- There is a trade-off: extremely high test coverage vs. effort in test development
126129

127130
---
128131

@@ -138,20 +141,17 @@ assert condition, "message"
138141

139142
## Test-driven Development (TDD)
140143

141-
- Principle is to write a test and then write a code to fulfill the test.
144+
- Principle of writing a test and then write a code to fulfill the test.
142145
- Advantages:
143-
- In the end user ends up with a test alongside the code.
146+
- Leads to a robust test along with the implementation.
144147
- Eliminates confirmation bias of the user.
145-
- Writing tests gives clarity on what the code is supposed to do.
146-
- Disadvantage: known to not improve productivity.
148+
- Facilitates continuous integration.
149+
- Reduces need for debugging.
150+
- Disadvantages:
151+
- False security from tests.
152+
- Neglect of overall design.
147153

148-
---
149-
150-
## Checking-driven Development (CDD)
151-
152-
- Developer performs spot checks; sanity checks at intermediate stages
153-
- Simulation software often has heuristics which are easy to determine.
154-
- Keep performing same checks at different stages of development to ensure the code works.
154+
Source: https://en.wikipedia.org/wiki/Test-driven_development
155155

156156
---
157157

05_testing_and_ci/python_testing_demo.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,20 @@ pip install -U pytest
2424
- All tests can be run using the command-line tool called `pytest`. Just type `pytest` in the working directory and hit ENTER.
2525
- If pytest is installed in some other way, you might need to run it like `python -m pytest`.
2626
- One test is expected to fail. Reading the error message we understand that the failure occurs because floating-point variable comparison is not handled correctly.
27-
- We need to tell pytest that while comparing two floating-point variables the value needs to be correct only up to a certain tolerance limit. To do this the expected mean value needs to be changed by uncommenting the line in the following part of the code:
27+
- We need to tell pytest that while comparing two floating-point variables the value needs to be correct only up to a certain tolerance limit. To do this, the expected mean value needs to be changed by uncommenting the line in the following part of the code:
2828

2929
```python
3030
# Expected result
3131
expected_mean = 78.33
3232
# expected_result = pytest.approx(78.3, abs=0.01)
3333
```
3434

35-
- **Comparing floating point variables** needs to be handled in functions like `find_average` and is done using `pytest.approx(value, abs)`. The `abs` value is the tolerance up to which the floating-point value will be checked, that is `78.33 +/- 0.01`.
35+
- **Comparing floating point variables** needs to be handled in functions like `find_mean` and is done using `pytest.approx(value, abs)`. The `abs` value is the tolerance up to which the floating-point value will be checked, that is `78.33 +/- 0.01`.
3636
- Even if one test fails, pytest runs all the tests and gives a report on the failing test. The assertion failure report generated my pytest is also more detailed than the usual Python assertion report. When the test fails, the following is observed:
3737

3838
```bash
39-
=============================================== FAILURES ====================================================
40-
____________________________________________ test_find_mean _________________________________________________
39+
========================================== FAILURES ===============================================
40+
_______________________________________ test_find_mean ____________________________________________
4141

4242
def test_find_mean():
4343
"""
@@ -73,20 +73,21 @@ tests/
7373
```
7474

7575
- Putting the tests in a folder `tests/` does not affect the behavior of pytest. When pytest is run from the original directory, the tests are found and run.
76+
- **Note**: revert to the old directory structure before proceeding to the next section.
7677

7778
## unittest
7879

79-
- Base class `unittest.TestCase` is used to create a test suite consisting of all the tests of a software.
80+
- Base class `unittest.TestCase` is used to create a test suite.
8081
- Each test is now a function of a class which is derived from the class `unittest.TestCase`.
8182
- The same tests as for `pytest` are implemented using `unittest` in the file `test_operations_unittests.py`. The tests are functions of a class named `TestOperations` which tests our mathematical operations. The class `TestOperations` is derived from `unittest.TestCase`.
82-
- unittest can be run by:
83+
- unittest can be run as a Python module:
8384

8485
```bash
8586
python -m unittest
8687
```
8788

88-
- unittest.TestCase offers functions like `assertEqual`, `assertAlmostEqual`, `assertTrue`, etc. for use instead of the usual assertion statements. These statements help the test runner to accumulate all test results and generate a test report.
89-
- `unittest.main()` provides an option to run the tests from a command-line interface.
89+
- unittest.TestCase offers functions like `assertEqual`, `assertAlmostEqual`, `assertTrue`, and more ([see unittest.TestCase documentation](https://docs.python.org/3/library/unittest.html#unittest.TestCase)) for use instead of the usual assertion statements. These statements ensure that test runner to accumulate all test results and generate a test report.
90+
- `unittest.main()` provides an option to run the tests from a command-line interface and also from a file.
9091
- `setUp` function is executed before all the tests. Similar a clean up function `tearDown` exists.
9192
- The intention is to group together sets of similar tests in an instant of `unittest.TestCase` and have multiple such instances.
9293
- Decorators such as `@unittest.skip`, `@unittest.skipIf`, `@unittest.expectedFailure` can be used to gain flexibility over working of tests.
@@ -123,22 +124,21 @@ coverage html
123124

124125
## tox
125126

126-
- Automation for Python testing (and much more)
127-
- Virtual environments are created for each task, and tox takes care of installing dependencies and the package itself inside of the environment.
128-
- Order of preference for files that tox tries to read: `pyproject.toml`, `tox.ini`, `setup.cfg`
129-
- `tox.ini` file
127+
- Environment orchestrator to setup and execute various tools for a project.
128+
- `tox` creates virtual environments to run each tools in.
129+
- `tox.toml` file:
130130

131-
```ini
132-
[tox]
133-
envlist = my_env
134-
skipsdist = true
131+
```toml
132+
requires = ["tox>=4"]
133+
env_list = ["testing"]
135134

136-
[testenv]
137-
deps = pytest
138-
commands = pytest
135+
[env.testing]
136+
description = "Run pytest"
137+
deps = ["pytest>=8"]
138+
commands = [["pytest"]]
139139
```
140140

141-
- Global settings defined under section `[tox]` in the INI file.
142-
- Start tox by running the command `tox` in the directory where the `tox.ini` exists.
141+
- Global settings defined under section at the top of the `tox.toml` file.
142+
- Start tox by running the command `tox` in the directory where the `tox.toml` exists.
143143
- tox takes more time the first time it is run as it creates the necessary virtual environments. Virtual environment setup can be found in the `.tox` repository.
144144
- Observe that tox starts a virtual environment, installs the dependency (here `pytest`) and runs `pytest`.

05_testing_and_ci/python_testing_exercise.md

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,25 @@
22

33
## Starting Remarks
44

5-
- [Exercise repository link](https://github.com/Simulation-Software-Engineering/testing-python-exercise-wt2223)
6-
- Deadline for submitting this exercise is **Thursday 26th January 2023 09:00**.
7-
- Structure all the tests in a format similar to what is shown in the [demo code](https://github.com/Simulation-Software-Engineering/Lecture-Material/blob/main/05_testing_and_ci/examples/python_testing).
5+
- [Exercise repository link](https://github.com/Simulation-Software-Engineering/testing-python-exercise-wt2425)
6+
- Deadline for submitting this exercise is **Wednesday 22nd January 2025 09:00**.
87

98
## Prerequisites
109

1110
- An operating system / software / environment where you can install Python and some basic Python tools
1211
- An editor or IDE to edit Python code and write text files
13-
- The following Python tools:
14-
- Python (version >= 3)
15-
- [pip](https://pypi.org/project/pip/)
16-
- [NumPy](https://numpy.org/)
17-
- [Matplotlib](https://matplotlib.org/)
18-
- [pytest](https://docs.pytest.org/en/6.2.x/getting-started.html#install-pytest)
19-
- [unittest](https://docs.python.org/3/library/unittest.html#module-unittest)
20-
- [coverage](https://coverage.readthedocs.io/en/6.2/#quick-start)
21-
- [tox](https://tox.wiki/en/4.0.15/installation.html)
12+
- Python (version >= 3)
13+
- [pip](https://pypi.org/project/pip/)
14+
- [NumPy](https://numpy.org/)
15+
- [Matplotlib](https://matplotlib.org/)
16+
- [pytest](https://docs.pytest.org/en/6.2.x/getting-started.html#install-pytest)
17+
- [unittest](https://docs.python.org/3/library/unittest.html#module-unittest)
18+
- [coverage](https://coverage.readthedocs.io/en/6.2/#quick-start)
19+
- [tox](https://tox.wiki/en/4.23.2/installation.html)
2220

2321
## Step 1 - Getting Familiar With the Code
2422

25-
- Fork the [repository](https://github.com/Simulation-Software-Engineering/testing-python-exercise-wt2223).
23+
- Fork the [repository](https://github.com/Simulation-Software-Engineering/testing-python-exercise-wt2425).
2624
- The code in `diffusion2d.py` is in principle the same code used for the Python packaging exercise. The main difference is that now the code has a class `SolveDiffusion2D` which has several member functions.
2725
- Each function name states what the function does, for example the function `initialize_domain()` takes in input arguments `w` (width), `h` (height), `dx` and `dy` and sets the values to member variables of the class and also calculates the number of points in x and y directions.
2826
- The functions `initialize_domain` and `initialize_physical_parameters` have default values for all input parameters, hence they can be called without any parameters.
@@ -51,7 +49,7 @@
5149
- Note that you have the object of the class `SolveDiffusion2D` and hence you can access member variables, for example `solver.nx` and `solver.ny`. This is useful to check the actual values.
5250
- Using a similar workflow, complete the other two unit tests.
5351
- Run the tests using `pytest`.
54-
- It is observed that in some instances `pytest` is not able to find the tests. One reason is the way pytest is installed, which is typically either using `pip` or `apt`. Refer to the [corresponding section](https://github.com/Simulation-Software-Engineering/Lecture-Material/blob/main/05_testing_and_ci/python_testing_demo.md#pytest) in the demo for more details. If such errors occur, then try to explicitly point pytest to the relevant test file. For example:
52+
- It is observed that in some instances `pytest` is not able to find the tests. One reason is the way pytest is installed, which is typically either using `pip` or `apt`. Refer to the [corresponding section](https://github.com/Simulation-Software-Engineering/Lecture-Material/blob/main/05_testing_and_ci/python_testing_demo.md#pytest) in the demo for more details. If such errors occur, then try to explicitly point pytest to the relevant test file in the following way:
5553

5654
```bash
5755
pytest tests/unit/test_diffusion2d_functions.py
@@ -99,13 +97,13 @@ pytest tests/unit/test_diffusion2d_functions.py
9997

10098
- Using the coverage tool generate a HTML report of the code coverage of all the tests.
10199
- Open the report file in a browser and print the report to a file called `coverage-report.pdf`. Add this file to the repository.
102-
- **Note**: coverage can be used with both `pytest` and `unittest`. In this case generating the report of the unit tests using unittest is sufficient.
100+
- **Note**: coverage can be used with both `pytest` and `unittest`. In this case, generating the report of the unit tests using unittest is sufficient.
103101

104102
## Step 7 - Automation Using tox
105103

106-
- Write a `tox.ini` file such that by running the command `tox`, both `pytest` and `unittest` are executed.
104+
- Write a `tox.toml` file such that by running the command `tox`, both `pytest` and `unittest` are executed.
107105
- Use the `requirements.txt` file to send all the dependencies information to tox.
108106

109107
## Step 8 - Submission
110108

111-
- Open a pull request titled `Adding tests by <GitLab username>` from your fork to the main repository.
109+
- Open a pull request titled `[<your GitLab username>] Adding tests` (for example: `[desaiin] Adding tests`) from your fork to the main branch of the exercise repository.

05_testing_and_ci/python_testing_slides.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ slideOptions:
4646

4747
- Python framework specifically designed to run, monitor and automate unit tests.
4848
- Many features like test automation, sharing of setup and shutdown of tests, etc.
49-
- Using the base class `unittest.TestCase` to create a test suite.
49+
- Use the base class `unittest.TestCase` to create a test suite.
5050
- Command-line interface: `python -m unittest test_module1 test_module2 ...`.
5151

5252
---
@@ -69,19 +69,27 @@ slideOptions:
6969

7070
## tox
7171

72-
- Automation for Python testing, building and distribution
73-
- Creates virtual environments for each process
74-
- Depending on the command, dependencies are installed, tests are run, packaging is done, etc.
75-
- tox command line tool reads and runs files like `pyproject.toml`, `tox.ini`, and `setup.cfg`
76-
- More information in the [tox wiki](https://tox.wiki/en/4.0.15/index.html).
72+
- Environment orchestrator to setup and execute various tools for a project.
73+
- Creates virtual environments for each process.
74+
- Processes include testing, linting, building, documentation generation, and more.
75+
- Configuration via `tox.toml` or `tox.ini` file.
7776

7877
---
7978

8079
## tox Demo
8180

8281
---
8382

84-
## Further reading
83+
## Other Testing Frameworks
84+
85+
- [nose](https://pypi.org/project/nose2/) is an extension to `unittest` with added plugins.
86+
- [testify](https://pypi.org/project/testify/) based on unittest and nose with additional features.
87+
- [robotframework](https://pypi.org/project/robotframework/) is a generic automation framework.
88+
89+
---
90+
91+
## Further Reading
8592

8693
- [pytest documentation](https://docs.pytest.org/en/6.2.x/)
8794
- [unittest documentation](https://docs.python.org/3/library/unittest.html)
95+
- [tox user guide](https://tox.wiki/en/4.23.2/user_guide.html#user-guide)

0 commit comments

Comments
 (0)