summerschool_simtech_2023/material/2_tue/testing/slides.md

224 lines
5.5 KiB
Markdown
Raw Normal View History

---
2023-10-09 09:03:54 +02:00
type: slide
slideOptions:
transition: slide
width: 1400
height: 900
margin: 0.1
---
2023-10-09 09:03:54 +02:00
<style>
.reveal strong {
font-weight: bold;
color: orange;
}
.reveal p {
text-align: left;
}
.reveal section h1 {
color: orange;
}
.reveal section h2 {
color: orange;
}
.reveal code {
font-family: 'Ubuntu Mono';
color: orange;
}
.reveal section img {
background:none;
border:none;
box-shadow:none;
}
</style>
# Learning Goals
- Get to know a few common terms of testing
- Work with the Julia unit testing package `Test.jl`
2023-10-09 15:49:03 +02:00
Material is taken and modified from the [SSE lecture](https://github.com/Simulation-Software-Engineering/Lecture-Material), which builds partly on the [py-rse book](https://merely-useful.tech/py-rse), and from the [Test.jl docs](https://docs.julialang.org/en/v1/stdlib/Test/).
---
# 1. General Introduction to Testing
---
## What is Testing?
2023-10-09 15:49:03 +02:00
- Smelling old milk before using it
- A way to determine if a software is not producing reliable results and if so, what is the reason
- Manual testing vs. automated testing
---
## Why Should you Test your Software?
2023-10-09 15:49:03 +02:00
- Improve software reliability and reproducibility
- Make sure that changes (bugfixes, new features) do not affect other parts of software
- Generally all software is better off being tested regularly. Possible exceptions are very small codes with single users.
- Ensure that a released version of a software actually works.
---
## Some Ways to Test Software
- Assertions
- Unit testing
- Integration testing
- Regression testing
---
## Assertions
2023-10-09 15:49:03 +02:00
```julia
@assert condition "message"
```
- Principle of *defensive programming*
- Nothing happens when an assertion is true; throws error when false.
- Types of assertion statements:
- Precondition
- Postcondition
- Invariant
2023-10-09 15:49:03 +02:00
- A basic but powerful tool to test a software on-the-go
---
## Unit Testing
2023-10-09 15:49:03 +02:00
- Catching errors with assertions is good but preventing them is better.
- A *unit* is a single function in one situation.
- A situation is one amongst many possible variations of input parameters.
2023-10-09 15:49:03 +02:00
- User creates the **expected result** manually.
- **Actual result** is compared to the expected result by `@test`.
---
## Integration Testing
- Test whether several units work in conjunction.
- *Integrate* units and test them together in an *integration* test.
2023-10-09 15:49:03 +02:00
- Often more complicated than a unit test and gives higher test coverage.
---
## Regression Testing
- Generating an expected result is not possible in some situations.
2023-10-09 15:49:03 +02:00
- Compare the *current* actual result with a *previous* actual result.
- No guarantee that the current actual result is correct.
- Risk of a bug being carried over indefinitely.
- Main purpose is to identify changes in the current state of the code with respect to a past state.
---
# 2. Unit Testing in Julia with Test.jl
---
2023-10-09 15:49:03 +02:00
## Setup of Test.jl
- Standardized folder structure:
2023-10-09 15:49:03 +02:00
```
├── Manifest.toml
├── Project.toml
├── src/
└── test
├── Manifest.toml
├── Project.toml
├── runtests.jl
└── setup.jl
```
- Singular `test` vs plural `runtests.jl`
- `setup.jl` for all `using XYZ` statements, included in `runtests.jl`
2023-10-09 15:49:03 +02:00
- Additional packages in `[extra] section` of `./Project.toml` or in new `./test/Project.toml`
- In case of the latter: Do not add the package itself to the `./test/Project.toml`
2023-10-09 15:49:03 +02:00
- Run: `]test` when root project is activated
---
## Implement and Structure Tests
- `@test expr`: Test whether expression `expr` is true
- `@test expr broken=true`: Explicitly mark test as broken
- `@test_throws exception expr`: Test whether expression `expr` throws `exception` (test unhappy path)
```julia
julia> @test_throws DimensionMismatch [1, 2, 3] + [1, 2]
Test Passed
Thrown: DimensionMismatch
```
- `@testset`: Structure tests
```julia
2023-10-09 15:49:03 +02:00
@testset "trigonometric identities" begin
θ = 2/3*π
@test sin(-θ) ≈ -sin(θ)
@test cos(-θ) ≈ cos(θ)
end;
```
- `@testset for ... end`: Test in loop
---
## Further Reading and Watching
- [Research Software Engineering with Python - Chapter 11: Testing Software](https://merely-useful.tech/py-rse/testing.html)
- [HiRSE-Summer of Testing Part 2b: "Testing with Julia" by Nils Niggemann](https://www.youtube.com/watch?v=gSMKNbZOpZU)
- [Official documentation of Test.jl](https://docs.julialang.org/en/v1/stdlib/Test/)
2023-10-09 15:49:03 +02:00
---
# 3. Test.jl Demo
We use [`MyTestPackage`](https://github.com/s-ccs/summerschool_simtech_2023/tree/main/material/2_tue/testing/MyTestPackage), which looks as follows:
```
├── Manifest.toml
├── Project.toml
├── src
│   ├── find.jl
│   └── MyTestPackage.jl
└── test
├── find.jl
├── Manifest.toml
├── Project.toml
├── runtests.jl
└── setup.jl
```
- Look at `MyTestPackage.jl` and `find.jl`: We have two functions `find_max` and `find_mean`, which calculate the maximum and mean of all elements of a `::AbstractVector`.
- Assertions were added to check for `NaN` values
- Look at `runtests.jl`:
2023-10-09 15:49:03 +02:00
- Why do we need `using MyTestPackage`?
- We include dependencies via `setup.jl`: `Test` and `StableRNG`.
- Testset "find"
- Look at `find.jl`
- Unit tests for `find_max` and `find_mean`
- `test_throws` to test unhappy path
- Test with absolute tolerance
- Integration test, which tests combination of both methods
- Run tests:
```
]activate .
]test
```
---
# 4. Exercise
Write tests for your own statistics package 😊