chapter five

5 Testing

 

This chapter covers software testing. We will split the content in two parts: - Fundamentals: Core concepts related to testing as a whole, to better understand testing holistically. - Unit tests: A focus on unit tests-related concepts to write better unit tests.

5.1 Fundamentals

In this section, we will explore fundamental testing concepts to help us framing a better idea of what testing is and why it matters in the end to write better software.

5.1.1 Avoiding Logic in Tests

Avoiding logic in tests in one of the most fundamental concepts to write more maintainable tests. Let’s first discuss an example to illustrate what logic means in tests.

Consider the following code, which calculates the total savings (or economy) we can realize by applying a discount percentage to a list of prices:

func economy(prices []float64, discountPercentage float64) float64 {
    var total float64
    for _, price := range prices {
        total += price * (-discountPercentage / 100)
    }
    return total
}

Now, we want to write a unit test to validate this economy function. We might want to reuse the same logic as the function itself to compute the expected result in the test like this:

5.1.2 Code Coverage

5.1.3 Line vs. Branch Coverage

5.2 Property-Based Testing

5.2.1 Traditional Tests

5.2.2 The Limitations of Traditional Tests

5.2.3 Exploring Property-Based Testing

5.2.4 Going Beyond

5.3 Unit Tests

5.3.1 Common Arguments Against Unit Tests

5.3.2 The code is too simple to need tests

5.3.3 I will add tests later

5.3.4 Testing is for testers

5.3.5 We will catch issues during integration tests

5.3.6 This code is just temporary, so it doesn’t need tests

5.3.7 I don’t have time to write unit tests

5.3.8 This code didn’t have unit tests, so why start now?

5.3.9 This project is just a PoC; it won’t go into production

5.3.10 It’s just a cleanup, no need to add tests

5.3.11 10 Unit Tests Properties

5.4 Unit Tests As Documentation