Skip to content

Commit 8db6daf

Browse files
committed
Merge branch 'main' into regression_new
# Conflicts: # learners/setup.md
2 parents dd9f6b2 + b66ce20 commit 8db6daf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1395
-2212
lines changed

CODE_OF_CONDUCT.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ we pledge to follow the [University of Sheffield Research Software Engineering C
77

88
Instances of abusive, harassing, or otherwise unacceptable behavior
99
may be reported by following our [reporting guidelines][coc-reporting].
10+
Please contact the [course organiser](mailto:liam.pattinson@york.ac.uk)
11+
with any complaints.
1012

1113
[coc-reporting]: https://rse.shef.ac.uk/community/code_of_conduct#enforcement-guidelines
1214
[coc]: https://rse.shef.ac.uk/community/code_of_conduct

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ use [GitHub flow][github-flow] to manage changes:
4646

4747
NB: The published copy of the lesson is usually in the `main` branch.
4848

49-
[repo]: https://github.com/Romain-Thomas-Shef/FAIR_Management_plan
50-
[repo-issues]: https://github.com/Romain-Thomas-Shef/FAIR_Management_plan/issues
51-
[contact]: mailto:romain.thomas@sheffield.ac.uk
49+
[repo]: https://github.com/researchcodingclub/python-testing-for-research
50+
[repo-issues]: https://github.com/researchcodingclub/python-testing-for-research/issues
51+
[contact]: mailto:liam.pattinson@york.ac.uk
5252
[github]: https://github.com
5353
[github-flow]: https://guides.github.com/introduction/flow/
5454
[github-join]: https://github.com/join

LICENSE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ Attribution](https://creativecommons.org/licenses/by/4.0/) licence.
1313
[Changes have been
1414
made](https://github.com/RSE-Sheffield/fair4rs-lesson-setup) to adapt the
1515
template to the specific context of the University of Sheffield's FAIR
16-
for Research Software training programme.
16+
for Research Software training programme, and altered further by
17+
the University of York [Research Coding Club](https://researchcodingclub.github.io/).
1718

1819
Unless otherwise noted, the instructional material in this lesson is
1920
made available under the [Creative Commons Attribution
@@ -35,7 +36,7 @@ Under the following terms:
3536

3637
- **Attribution**---You must give appropriate credit (mentioning that
3738
your work is derived from work that is Copyright (c) The University
38-
of Sheffield and, where practical, provide a [link to the
39+
of York and, where practical, provide a [link to the
3940
license][cc-by-human], and indicate if changes were made. You may do
4041
so in any reasonable manner, but not in any way that suggests the
4142
licensor endorses you or your use.
@@ -59,7 +60,7 @@ Except where otherwise noted, the example programs and other software
5960
provided in this work are made available under the [OSI][osi]-approved
6061
[MIT license][mit-license].
6162

62-
Copyright (c) The University of Sheffield
63+
Copyright (c) The University of York
6364

6465
Permission is hereby granted, free of charge, to any person obtaining a copy of
6566
this software and associated documentation files (the "Software"), to deal in

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ A short course on the basics of software testing in Python using the `pytest` li
44

55
This lesson uses [The Carpentries Workbench][workbench] template.
66

7+
It is derived from the [FAIR2 for Research Software](https://fair2-for-research-software.github.io/)
8+
training course [python-testing-for-research](https://github.com/FAIR2-for-research-software/python-testing-for-research)
9+
by the University of Sheffield.
10+
711
## Course Description
812

913
Whether you are a seasoned developer or just write the occasional script, it's important to know that your code does what you intend, and will continue to do so as you make changes.
@@ -18,7 +22,7 @@ This course seeks to provide you with conceptual understanding and the tools you
1822
- Running a test suite & understanding outputs
1923
- Best practices
2024
- Testing for errors
21-
- Testing data structures
25+
- Testing floating point data
2226
- Fixtures
2327
- Parametrisation
2428
- Testing file outputs
@@ -30,18 +34,27 @@ Contributions are welcome, please refer to the [contribution guidelines](CONTRIB
3034

3135
### Build the lesson locally
3236

33-
To render the lesson locally, you will need to have [R][r] installed. Instructions for using R with the Carpentries template is [available](https://carpentries.github.io/workbench/#installation) but some additional setps have been taken to make sure the enivronment is reproducible using the [`{renv}`](https://rstudio.github.io/renv/articles/renv.html) package and an `renv.lockfile` is included which allows the environment to be re-created along with dependencies.
37+
To render the lesson locally, you will need to have [R][r] installed.
38+
Instructions for using R with the Carpentries template is available on the
39+
[Carpentries website](https://carpentries.github.io/workbench/#installation).
40+
We recommend using the
41+
[`{renv}`](https://rstudio.github.io/renv/articles/renv.html) package.
42+
43+
After cloning the repository, you can set up `renv` and install all packages with:
3444

35-
After cloning the repository, you can set up the `renv` and install all packages with:
3645
``` r
37-
renv::restore()
46+
renv::init()
3847
# Optionally update packages
3948
renv::update()
4049
```
4150
Once you have installed the dependencies, you can render the pages locally by starting R in the project root and running:
51+
4252
``` r
4353
sandpaper::serve()
4454
```
55+
56+
When building the site subsequently, you may need to run `renv::activate()` first.
57+
4558
This will build the pages and start a local web-server in R and open it in your browser. These pages are "live" and will respond to local file changes if you save them.
4659

4760
[git]: https://git-scm.com

config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ episodes:
6565
- 03-interacting-with-tests.Rmd
6666
- 04-unit-tests-best-practices.Rmd
6767
- 05-testing-exceptions.Rmd
68-
- 06-testing-data-structures.Rmd
68+
- 06-floating-point-data.Rmd
6969
- 07-fixtures.Rmd
7070
- 08-parametrization.Rmd
7171
- 09-testing-output-files.Rmd

episodes/00-introduction.Rmd

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ exercises: 2
2222
This course aims to equip researchers with the skills to write effective tests and ensure the quality and reliability of their research software. No prior testing experience is required! We'll guide you through the fundamentals of software testing using Python's Pytest framework, a powerful and beginner-friendly tool. You'll also learn how to integrate automated testing into your development workflow using continuous integration (CI). CI streamlines your process by automatically running tests with every code change, catching bugs early and saving you time. By the end of the course, you'll be able to write clear tests, leverage CI for efficient development, and ultimately strengthen the foundation of your scientific findings.
2323

2424
This course has a single continuous project that you will work on throughout the lessons and each lesson builds on the last through practicals that will help you apply the concepts you learn. However if you get stuck or fall behind during the course, don't worry!
25-
All the stages of the project for each lesson are available in the `files` directory in this course's materials that you can copy across if needed. For example if you are on lesson 3 and haven't completed the practicals for lesson 2, you can copy the corresponding folder from the `files` directory.
25+
All the stages of the project for each lesson are available in the `learners/files` directory in this [course's materials](https://github.com/researchcodingclub/python-testing-for-research) that you can copy across if needed. For example if you are on lesson 3 and haven't completed the practicals for lesson 2, you can copy the corresponding folder from the `learners/files` directory.
2626

2727
By the end of this course, you should:
2828

@@ -72,9 +72,9 @@ This course uses blocks like the one below to indicate an exercise for you to at
7272

7373
::::::::::::::::::::::::::::::::::::: keypoints
7474

75-
- This course will teach you how to write effective tests and ensure the quality and reliability of your research software
76-
- No prior testing experience is required
77-
- You can catch up on practicals by copying the corresponding folder from the `files` directory of this course's materials
75+
- This course will teach you how to write effective tests and ensure the quality and reliability of your research software.
76+
- No prior testing experience is required.
77+
- You can catch up on practicals by copying the corresponding folder from the `learners/files` directory of this [course's materials](https://github.com/researchcodingclub/python-testing-for-research).
7878

7979
::::::::::::::::::::::::::::::::::::::::::::::::
8080

episodes/01-why-test-my-code.Rmd

Lines changed: 91 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,22 @@ exercises: 2
1818

1919
## What is software testing?
2020

21-
Software testing is the process of checking that code is working as expected. You may have data processing functions or automations that you use in your work - how do you know that they are doing what you expect them to do?
21+
Software testing is the process of checking that code is working as expected.
22+
You may have data processing functions or automations that you use in your work.
23+
How do you know that they are doing what you expect them to do?
2224

23-
Software testing is most commonly done by writing code (tests) that check that your code works as expected.
25+
Software testing is most commonly done by writing test code that check that
26+
your code works as expected.
2427

25-
This might seem like a lot of effort, so let's go over some of the reasons you might want to add tests to your project.
28+
This might seem like a lot of effort, so let's go over some of the reasons you
29+
might want to add tests to your project.
2630

2731

2832
## Catching bugs
2933

30-
Whether you are writing the occasional script or developing a large software, mistakes are inevitable. Sometimes you don't even know when a mistake creeps into the code, and it gets published.
34+
Whether you are writing the occasional script or developing a large software,
35+
mistakes are inevitable. Sometimes you don't even know when a mistake creeps
36+
into the code, and it gets published.
3137

3238
Consider the following function:
3339

@@ -36,50 +42,63 @@ def add(a, b):
3642
return a - b
3743
```
3844

39-
When writing this function, I made a mistake. I accidentally wrote `a - b` instead of `a + b`. This is a simple mistake, but it could have serious consequences in a project.
45+
When writing this function, I made a mistake. I accidentally wrote `a - b`
46+
instead of `a + b`. This is a simple mistake, but it could have serious
47+
consequences in a project.
4048

41-
When writing the code, I could have tested this function by manually trying it with different inputs and checking the output, but:
49+
When writing the code, I could have tested this function by manually trying it
50+
with different inputs and checking the output, but:
4251

4352
- This takes time.
4453
- I might forget to test it again when we make changes to the code later on.
45-
- Nobody else in my team knows if I tested it, or how I tested it, and therefore whether they can trust it.
54+
- Nobody else in my team knows if I tested it, or how I tested it, and
55+
therefore whether they can trust it.
4656

4757
This is where automated testing comes in.
4858

4959
## Automated testing
5060

51-
Automated testing is where we write code that checks that our code works as expected. Every time we make a change, we can run our tests to automatically make sure that our code still works as expected.
61+
Automated testing is where we write code that checks that our code works as
62+
expected. Every time we make a change, we can run our tests to automatically
63+
make sure that our code still works as expected.
5264

53-
If we were writing a test from scratch for the `add` function, think for a moment on how we would do it.
54-
We would need to write a function that runs the `add` function on a set of inputs, checking each case to ensure it does what we expect. Let's write a test for the `add` function and call it `test_add`:
65+
If we were writing a test from scratch for the `add` function, think for a
66+
moment on how we would do it.
67+
68+
We would need to write a function that runs the `add` function on a set of
69+
inputs, checking each case to ensure it does what we expect. Let's write a test
70+
for the `add` function and call it `test_add`:
5571

5672
```python
5773
def test_add():
58-
# Check that it adds two positive integers
59-
if add(1, 2) != 3:
60-
print("Test failed!")
61-
# Check that it adds zero
62-
if add(5, 0) != 5:
63-
print("Test failed!")
64-
# Check that it adds two negative integers
65-
if add(-1, -2) != -3:
66-
print("Test failed!")
74+
# Check that it adds two positive integers
75+
if add(1, 2) != 3:
76+
print("Test failed!")
77+
# Check that it adds zero
78+
if add(5, 0) != 5:
79+
print("Test failed!")
80+
# Check that it adds two negative integers
81+
if add(-1, -2) != -3:
82+
print("Test failed!")
6783
```
6884

69-
Here we check that the function works for a set of test cases. We ensure that it works for positive numbers, negative numbers, and zero.
85+
Here we check that the function works for a set of test cases. We ensure that
86+
it works for positive numbers, negative numbers, and zero.
7087

7188

7289
::::::::::::::::::::::::::::::::::::: challenge
7390

74-
## Challenge 1: What could go wrong?
91+
## What could go wrong?
7592

76-
When writing functions, sometimes we don't anticipate all the ways that they could go wrong.
93+
When writing functions, sometimes we don't anticipate all the ways that they
94+
could go wrong.
7795

78-
Take a moment to think about what is wrong, or might go wrong with these functions:
96+
Take a moment to think about what is wrong, or might go wrong with these
97+
functions:
7998

8099
```python
81100
def greet_user(name):
82-
return "Hello" + name + "!"
101+
return "Hello" + name + "!"
83102
```
84103

85104
```python
@@ -89,38 +108,40 @@ def gradient(x1, y1, x2, y2):
89108

90109
:::::::::::::::::::::::: solution
91110

92-
## Answer
93-
94-
The first function will incorrectly greet the user, as it is missing a space after "Hello". It would print `HelloAlice!` instead of `Hello Alice!`.
111+
The first function will incorrectly greet the user, as it is missing a space
112+
after "Hello". It would print `HelloAlice!` instead of `Hello Alice!`.
113+
114+
If we wrote a test for this function, we would have noticed that it was not
115+
working as expected:
95116

96-
If we wrote a test for this function, we would have noticed that it was not working as expected:
97117
```python
98118
def test_greet_user():
99-
if greet_user("Alice") != "Hello Alice!":
100-
print("Test failed!")
119+
if greet_user("Alice") != "Hello Alice!":
120+
print("Test failed!")
101121
```
102122

103123
The second function will crash if `x2 - x1` is zero.
104124

105-
If we wrote a test for this function, it may have helped us to catch this unexpected behaviour:
125+
If we wrote a test for this function, it may have helped us to catch this
126+
unexpected behaviour:
106127

107128
```python
108129
def test_gradient():
109-
if gradient(1, 1, 2, 2) != 1:
110-
print("Test failed!")
111-
if gradient(1, 1, 2, 3) != 2:
112-
print("Test failed!")
113-
if gradient(1, 1, 1, 2) != "Undefined":
114-
print("Test failed!")
130+
if gradient(1, 1, 2, 2) != 1:
131+
print("Test failed!")
132+
if gradient(1, 1, 2, 3) != 2:
133+
print("Test failed!")
134+
if gradient(1, 1, 1, 2) != "Undefined":
135+
print("Test failed!")
115136
```
116137

117-
And we could have ammened the function:
138+
And we could have amended the function:
118139

119140
```python
120141
def gradient(x1, y1, x2, y2):
121-
if x2 - x1 == 0:
122-
return "Undefined"
123-
return (y2 - y1) / (x2 - x1)
142+
if x2 - x1 == 0:
143+
return "Undefined"
144+
return (y2 - y1) / (x2 - x1)
124145
```
125146

126147
:::::::::::::::::::::::::::::::::
@@ -129,59 +150,72 @@ def gradient(x1, y1, x2, y2):
129150

130151
## Finding the root cause of a bug
131152

132-
When a test fails, it can help us to find the root cause of a bug. For example, consider the following function:
153+
When a test fails, it can help us to find the root cause of a bug. For example,
154+
consider the following function:
133155

134156
```python
135157

136158
def multiply(a, b):
137-
return a * a
159+
return a * a
138160

139161
def divide(a, b):
140-
return a / b
162+
return a / b
141163

142164
def triangle_area(base, height):
143-
return divide(multiply(base, height), 2)
165+
return divide(multiply(base, height), 2)
144166
```
145167

146-
There is a bug in this code too, but since we have several functions calling each other, it is not immediately obvious where the bug is. Also, the bug is not likely to cause a crash, so we won't get a helpful error message telling us what went wrong. If a user happened to notice that there was an error, then we would have to check `triangle_area` to see if the formula we used is right, then `multiply`, and `divide` to see if they were working as expected too!
168+
There is a bug in this code too, but since we have several functions calling
169+
each other, it is not immediately obvious where the bug is. Also, the bug is
170+
not likely to cause a crash, so we won't get a helpful error message telling us
171+
what went wrong. If a user happened to notice that there was an error, then we
172+
would have to check `triangle_area` to see if the formula we used is right,
173+
then `multiply`, and `divide` to see if they were working as expected too!
147174

148-
However, if we had written tests for these functions, then we would have seen that both the `triangle_area` and `multiply` functions were not working as expected, allowing us to quickly see that the bug was in the `multiply` function without having to check the other functions.
175+
However, if we had written tests for these functions, then we would have seen
176+
that both the `triangle_area` and `multiply` functions were not working as
177+
expected, allowing us to quickly see that the bug was in the `multiply`
178+
function without having to check the other functions.
149179

150180

151181
## Increased confidence in code
152182

153-
When you have tests for your code, you can be more confident that it works as expected. This is especially important when you are working in a team or producing software for users, as it allows everyone to trust the code. If you have a test that checks that a function works as expected, then you can be confident that the function will work as expected, even if you didn't write it yourself.
183+
When you have tests for your code, you can be more confident that it works as
184+
expected. This is especially important when you are working in a team or
185+
producing software for users, as it allows everyone to trust the code. If you
186+
have a test that checks that a function works as expected, then you can be
187+
confident that the function will work as expected, even if you didn't write it
188+
yourself.
154189

155190
## Forcing a more structured approach to coding
156191

157-
When you write tests for your code, you are forced to think more carefully about how your code behaves and how you will verify that it works as expected. This can help you to write more structured code, as you will need to think about how to test it as well as how it could fail.
192+
When you write tests for your code, you are forced to think more carefully
193+
about how your code behaves and how you will verify that it works as expected.
194+
This can help you to write more structured code, as you will need to think
195+
about how to test it as well as how it could fail.
158196

159197
::::::::::::::::::::::::::::::::::::: challenge
160198

161-
## Challenge 2: What could go wrong?
199+
## What could go wrong?
162200

163201
Consider a function that controls a driverless car.
164202

165203
- What checks might we add to make sure it is not dangerous to use?
166204

167205
```python
168-
169206
def drive_car(speed, direction):
170207

171-
... # complex car driving code
208+
... # complex car driving code
172209

173210
return speed, direction, brake_status
174-
175-
176211
```
177212

178213
:::::::::::::::::::::::: solution
179214

180-
## Answer
181215

182216
- We might want to check that the speed is within a safe range.
183-
184-
- We might want to check that the direction is a valid direction. ie not towards a tree, and if so, the car should be applying the brakes.
217+
- We might want to check that the direction is a valid direction. ie not
218+
towards a tree, and if so, the car should be applying the brakes.
185219

186220
:::::::::::::::::::::::::::::::::::::
187221
::::::::::::::::::::::::::::::::::::::::

0 commit comments

Comments
 (0)