Property-Based Testing with test.check
Property-Based Testing is a powerful way to test your software. In this Beginning course, we learn how to use test.check, the Clojure Property-Based Testing library, to automatically generate tests. It is continued in Intermediate and Advanced.
Beginning Property-Based Testing with test.check
Want this course?
Love it or leave it guarantee
If you don't learn as much from this course as you thought, just ask for a refund within 30 days and I'll give you your money back.
1. What is Property-Based Testing?
Property-Based Testing is a way to generates lots and lots of tests so you don't have the write them. It finds bugs and helps you design your software. In this introduction to the course, we learn what Property-Based Testing is.
2. What is test.check?
test.check is the Property-Based Testing library we'll be using in this course. In this lesson, we'll take a look at the origin of this library, how it integrates with Clojure, and how it's getting a lot of attention from the Clojure core team.
3. Advantages of Property-Based Testing
Property-Based Testing has several advantages over regular Example-Based Testing. It's worth calling them out.
4. When can you use Property-Based Testing
Property-Based Testing can be used at four different times, from design-time to after your users have found a bug, to help you reproduce it.
5. How does Property-Based Testing work?
In this lesson, we go through the basic algorithm used by test.check to test our code and show us useful failures. The algorithm gives us a map of the things we will have to learn.
6. An overview of property-based testing with an example test
In this lesson, we will see an example of the process of testing an existing function using Property-Based Testing.
7. A tour of the built-in generators
test.check comes with many built-in generators that we can use to create properties and build new generators from. We take a tour of the generators provided so we have a feeling of what's available.
8. Building your own simple generators
We can put together generators that we need from the existing generators. There are four tools provided by test.check that help us do this. In this lesson, we go over such-that, fmap, bind, and let.
9. Strategies for properties: functionality
Coming up with properties is hard. So we need some strategies to try out when we need to come up with them. In this lesson, we go over two ways to directly test the functionality of a function.
10. Strategies for properties: invariants
Coming up with properties can be a challenge. One strategy is to look at what doesn't change. In this lesson, we take a look at testing invariants.
11. Strategies for properties: algebraic properties
I often run through a short list of algebraic properties, the ones you learn in Algebra class, to find properties to test. In this lesson, we go over six properties that you can use and modify to your needs.
12. Testing pure functions
Pure functions are the easiest things to test. You can run them as many times as you want without fear of side effects. In this long episode, watch over my shoulder as I test five different functions. Three of the functions are fairly mathematical, so they're pretty straightforward. But two are copied from real-world code. You'll get to see the raw process, right here.
13. When to test: before implementation
In this lesson, we implement a function using TDD. Property-based testing is great for doing TDD since the tests are constantly giving you small examples that fail, one at a time. Make it pass, and get another. Make that pass, get another. Eventually, you'll have the whole thing tested and implemented.
14. When to test: after implementation
Testing after an implementation exists and is working is often frowned upon. Your brain is biased toward your implementation, so it's hard to find good counterexamples. However, in Property-based testing, the system is generating tests, and it doesn't have a bias.
Although PBT is very valuable for testing after implementing, it still has two challenges. You still need to think of how to trick the tests without having the benefit of modifying the implementation. The second challenge is to avoid duplicating the implementation. A test that uses the same code as the function it tests is useless.
In this lesson we go through the process of testing an existing function. We write many tests, and settle on just a couple that seem to cover the entire functionality.