Test driven development and code quality
In scientific computing the interdependence of algorithms and their complexity requires rigorous testing and a high code quality.
Test driven development
Test driven development (TDD) is becoming a standard in (complex) software development. It means you first write tests and then implement your functionality to pass the test. TDD helps the programmer focus on functional requirements and thus leads to a cleaner and more thoroughly thought
API
.
A TDD-workflow consists of 2 phases:
- red phase
- implement tests (typically
unit tests
)
- execute tests
- implement functionality until tests pass
- green phase
- add
smoke tests
- add
production tests
- refactor the code: improve readability, design and performance until satisfactory
- move on to the next feature
Test infrastructure
To benefit from advanced testing functionalities and an easy test creation an established testing framework should be used. Benefits feature floating point comparisons and filtering of specific tests at
runtime
and sharing code/data between tests. Remember to first run unit and smoke tests and inspect their results, before running the extensive production tests.
Start setting up your tests with this article
Code quality
There are different measures to ensure code quality. Since they are general principles, only a short overview is given:
-
static checkers
, e.g. clang-tidy
- pseudocode programming (PP)
First outline the algorithm with pseudocode (write the pseudocode as comment). This is a quick task that helps you formulate your code quickly. Now implement what you have written in the pseudocode. Leave the pseudocode there as code documentation.
- meaningful names for variables, functions, classes etc.
Nowadays with auto-completion in many editors, there is not really a point using super-short names.
- make functions difficult to use incorrectly and easy to use correctly
- reduce the number of arguments, where possible
- place modified arguments always first or last
- provide forwards for functions with commutative arguments
This means having a function with the same name as the original but with swaped arguments (arguments need to have different types, e.g. int and str), that calls the actual function with the arguments in the right order and returns that value.
- remove copies
- single responsibility for functions/classes
This means a function/class should only should be responsible for one single task. It should e.g. not compute results and
render
them.
Where to start
For an example how some of your unit-tests might look like go to our literature on Test Driven Development. For smoke-tests refer to this example.
To start working go to How to set up local automatic testing or refer to the CI-chapter
You can also get a list of our articles assigned to this chapter via the tags on the top of every page.
See also