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 .

Workflow TDD

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