Testing Conventions

Note, these are guidelines used by the SCD Cloud Operations Group. They are being presented externally as they may be useful for those developing their own software, they are not being provided with the intention of the Cloud Team reviewing your code - unless you are contributing to one of our repositories.

 

Code should be well-tested before being contributed. There are a number of ways you can test your code, but we recommend you start with unit tests.

Unit Tests

Unit tests refer to testing individual components or units of code in isolation. We aim to ensure that each unit of code functions properly and that it meets intended behaviours. A unit can a function, method, class or module - depending on granularity of the code being tested.

Guidelines:
When writing unit tests consider the following:

  1. Readability
    A unit test should have a singular purpose and the name should reflect what is being tested and the expected behaviour.

  2. Independence
    A unit test should be independent of all others, and can be executed independent of all others.

  3. Maintainability
    'The less code to maintain the better' - avoid boilerplate code and testing the same thing twice.
    Extract common setup and tear-down code into reusable functions or separate tests.

  4. Coverage
    Aim for high code coverage by testing each different path and edge case.
    We don’t enforce a code coverage target

  5. Fail Noisily
    Ensure that when tests fail it is clear as to the reason why. Use descriptive assertions and error messages to aid debugging. Avoid overly generic assertions.

  6. Performance
    Unit test should execute quickly and provide fast feedback
    Don’t aim to test expensive I/O operations, network calls or time-consuming operations. Instead use mocks

  7. Documentation
    write docstrings for each test to describe what your testing and why - especially when testing obscure edge cases

Python Unit Testing

We can write automated unit tests for Python using a test runner. There are a number of test runners available:

Guidelines

Here are a set of testing guidelines for python

  • Use pytest parametrization for testing edge-cases

  • Use pytest fixtures to reduce setup and tear-down boilerplate in tests

  • Make use of python mocks to remove external dependencies

Test Driven Development (TDD)

Test-driven development is an approach to writing code that encourages you to write test before the actual code. It follows this basic approach

  1. Write a failing test

  2. Implement code to make the test pass

  3. Refactor the code, whilst keeping the test passing

TDD will help you organise your code into smaller modules and prioritise reusability
(because you’ll want to write less tests!)

This will in turn improve your code coverage and overall maintainability of your code.

Higher-level testing procedures

There are a number of other higher level testing procedures you could implement.
Higher-level tests help you to catch bugs from emergent behaviour - like testing if different modules work together as expected.

No Guidelines for higher-level testing yet. Use your best judgement

 

Integration tests:

Integration tests are tests that verify that each (unit-tested) module of your code interact as expected

  • useful for testing I/O operations and testing components out of isolation

End-to-End tests

These tests usually replicate user behaviour with the software in an application environment.
We usually run end-to-end tests for software on the Dev Cloud before making changes available on Production Cloud

Note: Testing is an iterative process. If you spot a bug, write tests for that bug, then fix the bug and ensure that the tests pass. That way, future versions will need to maintain that fix as well