Unit Testing#
Testing is the process of ensuring that our analysis and pipelines are actually working and giving us the right answers, as well as ensuring that changes or new features to a codebase don’t break something that currently works. This is done using tools which run our code on known, canned problems and compare the outputs to what is expected.
While testing is an absolute essential for large or community-maintained projects, it is never too early to implement testing in your own research code. It will make your code more robust, and also encourage good programming practices. There is even a mode of coding known as test-driven development, in which one writes the tests first, with the expected behavior, and then writes the actual functions to match.
Test driven development isn’t very applicable to most standard research code, but having tests can be very useful.
There are several testing frameworks out there; I use pytest
primarily, and will thus use that here.
Eventually, it is best to have a folder for testing separate from your installed code, but for now, we’ll simply make a file called test_code.py
in the same directory as the python scripts containing the functions or classes we want to test.
Exercise 1: The Function to Test
Make a python file in some folder called acceleration.py
, and inside, write a class Body
which initializes with a mass
and x
,y
,z
position. Then write a method for it called calc_acceleration(self,other_bdoy)
which calculates the acceleration to another body object assuming one is input. You may want to use astropy.units
.
Such a class might be the basis of an RK4 integrator or other simulation. We want to make sure our acceleration function works all the time!
Exercise 2: The Test
Now make a python file called test_acceleration.py
. Inside, import your Body
class (from acceleration import Body
).
We now need to write a test. Make a function, test_a()
, which takes no inputs. Inside it, create two Body objects. Choose masses and positions that are easy for you to compute by hand. Compute the answer for the acceleration of Body 1 due to Body2 using good ole’ pen and paper.
For the last line of your function, add an assert
statement, that says assert body1.calc_acceleration(body2) == pytest.approx(YOUR_COMPUTED_ANSWER,tol)
.
The tol
is how close the answer should be. If you use a different value for G between your function and your by-hand calculation, the answers won’t be exactly the same. Pick how many significant figures you think are reasonable for this calculation, then enter the relevant tol (e.g., 1e-5
).
Exercise 3: Run it
Now, (assuming pytest is installed), cd into the directory with the file and the test file, and simply run pytest
. It will automatically run tests in files that start with the word test. Does your function pass?
Once you have a passing test, you know that your method is producing sensible results. Later, if you discover a more efficient coding solution and modify that function, you can easily test that it still gives the right answer.
Even better, you can set up pytest to run automatically, on GitHub, every time you push new changes to your code. In this way, you are continuously monitoring your code as it grows and evolves over time. There are many more ways to to make tests more comprehensive and complex, so I encourage you to explore that throughout the summer.