Course Information

Government Analysis Function and Data Science Campus Logos.

1 Course Overview

Unit testing is a critical part of the software development process, ensuring that individual components of the code work as expected. In this course, you will learn how to write and run unit tests to verify that your functions are correct and reliable. Unit tests play an essential role in catching bugs early, improving code quality, and preventing issues when making changes to the program.

This course provides an introduction to the essential practice of unit testing in software development. Unit testing helps ensure that individual components of your program behave as expected and are reliable, making it a critical skill for building high-quality software.

  1. Introduction to Unit Testing In the first section, you’ll be introduced to the concept of unit testing. We will cover why unit testing is an essential part of the development process, focusing on how it helps maintain code quality, catch bugs early, and prevent regressions. You will also learn about test-driven development (TDD), which emphasizes writing tests before the actual code to guide the development process.

  2. Designing Good Functions In this section, we will discuss the key characteristics of well-designed, testable functions. You’ll learn how to write functions that are modular, clear, and easy to test. We’ll cover topics such as single responsibility, clarity, and the importance of making your functions predictable and side-effect free.

  3. Writing Unit Tests Here, you will gain hands-on experience in writing unit tests using Python’s built-in unittest framework. You’ll learn how to create test cases, assert expected behaviors, handle edge cases, and write tests that check for different types of errors and exceptions. You’ll also get to practice running your tests and interpreting the results.

  4. Exercises To reinforce the concepts covered in the course, a series of practical exercises will help you apply what you’ve learned. These exercises will guide you through writing unit tests for different functions and scenarios, including both simple and more complex examples. By the end of this section, you’ll be able to confidently write and execute unit tests for your own projects.

  5. Summary In this section, we’ll summarize the key takeaways from the course, highlighting the importance of unit testing and the best practices for writing reliable, testable code. You’ll be reminded of the tools and techniques introduced throughout the course to help you write and manage your tests effectively.

  6. Further Study This course is an introduction to unit testing and focuses on the basics. For learners interested in expanding their knowledge, we will provide resources for further study. These will include advanced topics such as testing frameworks for large-scale applications, testing data structures like dataframes, and integrating unit tests with more complex systems like Spark.

2 Introduction to Unit Testing

When developing software it is crucial that the developer is certain their code behaves as expected. For many beginners the way to test this is to call a program and do something along the lines of “seeing if it works”, checking the program gets the right output for what you are trying to do. This is good intuition; however, it is not the most effective way of checking a program.

Unit testing is the process of taking a part of code; primarily at a function level, giving it a range of inputs, then checking that the outputs of the function match what we expect the output to be. If the output of the function matches our expectation, the code passes the test, if it does not, it fails.

This allows us to check the function’s behaviours every time that we make a change to the code. When our code passes tests we can be confident that it will perform as expected. It is therefore important that we write good tests to measure the behaviour of our code.

Unit Testing Principles

Unit tests are tests that are performed independently of other tests. They allow us to check that the elements which make up our code do as expected. This does not ensure that those elements work well together.

pyramid of different test types, with unit tests at the bottom then integration tests, then end to end tests

What a “Unit” of code is defined as will depend on the application and context. A good approximation for the scale or “level of abstraction” of a unit of code is a function. Functions can easily be tested as they have a known input, and should therefore have a known output.

Unit testing allows developers to rapidly and repeatedly check code in a consistent manner. This means that as long as good tests have been written and then passed, the functions work.

Unit testing will not guarantee that your code is optimally structured or designed, but the tests will tell whether or not the code does what you think it is meant to do.

Test Driven Development

There are a wide range of methods to develop code. One commonly used method for writing code is Test Driven Development. This method is a flipped design approach. Instead of writing code then writing tests to check the performance, the tests are first written then the code.

By writing the tests first the specifications of what the code is supposed to do can be more strictly described.

The tests ensure that the code complies with all the specifications.

The units are written in order to pass the unit’s tests.

It is important that the tests check every aspect of the code’s behaviour. How much behaviour the tests cover is called test coverage.

Once the unit tests are complete, higher level tests can be completed such as integration or end to end tests which ensure the code units work together as expected.

This is an effective way to design code as:

  • Code outcomes are the focus of design.
  • Errors are more easily identifiable.
  • It is simple to check whether restructuring/rewriting breaks the working code.
  • Code written is simple, as it is designed to pass the tests and no more.

3 Designing Good Functions

Before creating unit tests it is important that we know what good functions look like, how they act and how to write them, so that they can be properly tested.

Throughout this course we are going to create, analyse and adapt two functions (i) one that calculates the mean and (ii) the other the standard deviation.

These functions are basic, but the principles of their design hold for other more complex processes.

Your own business area may have a style guide or particular approach to good practice in designing code - this should be followed. The syntax in this course is a general guide and introduction to some good practice.