Making Tests Repeatable
Let’s learn how to test functions that are not pure.
We'll cover the following...
Testing impure functions
All of our tests are inside our functional core. In the core, calling a function with the same arguments will almost always result in the same output. The word “almost” is dangerous, though, because our whole strategy involves comparing our expectations to actual values. When we can’t have expectations from run to run, we must change our approach.
Timestamps and random numbers
Sometimes, functions are not perfectly pure. Functions that create timestamps or random numbers are famously challenging to test. We have both types of functions in our codebase. For example, recall the response test:
test "a timestamp is added at build time", %{right: response} doassert %DateTime{ } = response.timestampassert response.timestamp < DateTime.utc_nowend
We deal with that problem by changing the way we think about expectations. Rather than testing against an exact value, we make sure the timestamp is, in fact, a timestamp and that it’s before the present moment, utc_now
.
Random numbers will be a little trickier. As we build our tests, we’ll dodge the random problem in most of them by building tests that restrict choices in one way or another. Let’s solve the easy problems first and save the toughest for last.
First, we need the typical test directives. We’ll create /test/question_test.exs
and key this in:
defmodule QuestionTest douse ExUnit.Caseuse QuizBuildersend