Examples
Test parameter generation
For a small test set, generate tests is quick.
test_set = all_pairs(
[(-3, -2), (2, 3), (-2, 3), (4.999, 5), (0, 1e7)],
[0.1, 0.01, 0.001],
[:RungeKutta, :Midpoint]
)
@testset "custom_integrate $test_case" for test_case in test_set
a, b = test_case[1]
result = custom_integrate(a, b, test_case[2:end]...)
@test result == compare_with_symbolic_integration(a, b)
end
Save larger test suites instead of regenerating
For a larger test set, it can be worthwhile to make test suites and save them.
wide_test = all_triples(fill(1:4, 30)...)
JLD.save("test_artifact.jld", "wide_test", wide_test)
These could then be made available for testing through Pkg.Artifacts.
Test data generation
This library will create test data as easily as it creates test cases. In the same way that testing different sets of arguments to a function improves test coverage, testing different datasets improves coverage. For instance, data_frame = all_data_frame[data_frame[:, :time] > 10]
has two branches, one for times less than ten and one for times greater than ten.
using DataFrames
names = ["time", "event", "who", "location"]
at = all_triples([0.1, 5.1, 10.9], [:infect, :recover], [10, 11], ["forest", "home"])
DataFrame(Dict(names[i] => [row[i] for row in at] for i in 1:length(names))...)
12 rows × 4 columns
event | who | location | time | |
---|---|---|---|---|
Symbol | Int64 | String | Float64 | |
1 | infect | 10 | forest | 0.1 |
2 | infect | 11 | home | 0.1 |
3 | recover | 10 | home | 0.1 |
4 | recover | 11 | forest | 0.1 |
5 | infect | 10 | home | 5.1 |
6 | infect | 11 | forest | 5.1 |
7 | recover | 10 | forest | 5.1 |
8 | recover | 11 | home | 5.1 |
9 | infect | 10 | forest | 10.9 |
10 | infect | 11 | home | 10.9 |
11 | recover | 10 | home | 10.9 |
12 | recover | 11 | forest | 10.9 |
Excursions
If you want to start with a single test that you know is a common way to call a function, then an excursion can generate variations around that common way. It picks one parameter and walks through its values. Then another. If you choose a pair-wise excursion, it walks all pairs away from the initial value.
values_excursion([1, 2], [true, false], ["c", "b", "a"])
5-element Vector{Vector{Any}}: [1, true, "c"] [2, true, "c"] [1, false, "c"] [1, true, "b"] [1, true, "a"]
Filtering a factorial
The full-factorial test generates every possible test. If some combinations of parameters aren't interesting or allowed for a function, you can exclude them by using an extra argument.
disallow = (a, b, c) -> b == 7 && c == false
full_factorial([1, 2, 3], [7, 8], [true, false]; disallow = disallow)
9-element Vector{Vector{Integer}}: [1, 7, true] [1, 8, true] [1, 8, false] [2, 7, true] [2, 8, true] [2, 8, false] [3, 7, true] [3, 8, true] [3, 8, false]