Given-When-Then is a style of representing tests of specifying a system's behaviour using specification by example - Martin Fowler.
This is a micro library that is a lite extension to ExUnit and prefers pattern matching over regular expressions. There are other BDD libraries but they do not seem to be maintained. The advantages of Given are:
- no regular expressions
- pattern match errors are clear and obvious
- line numbers in errors are accurate as there are no separate text files
We use a parser to split clauses into words, strings, integers and dates then
call functions and rely on pattern matching to build up a test state. The input
is the standard context created with the setup
and setup_all
callbacks
and this context is passed from clause to clause with new data appended.
Here is a working example using the peek at elixir-lang.org:
defmodule Given.ReadmeTest do
use ExUnit.Case
use Given.Case
describe "elixir-lang.org" do
scenario "peek", ~s"""
Given the string "Elixir"
When graphemes
And frequencies
Then "i" occurs 2 times
And "E" occurs 1 time
"""
end
# Pre-conditions
def given_({:the_string, s}, _), do: [str: s]
# Actions
def when_({:graphemes}, %{str: s}), do: [gs: String.graphemes(s)]
def when_({:frequencies}, %{gs: gs}), do: [freq: Enum.frequencies(gs)]
# Post-conditions
def then_({l, :occurs, n, _}, %{freq: freq}), do: assert n == freq[l]
end
See the Case module for the syntax of the scenarios and the Parser module contains the terms that can be used.
def deps do
[
{:given, "~> 1.22", only: [:test, :dev]}
]
end
When changing the grammar or the parser, run tests with:
PROPCHECK_NUMTESTS=20000 mix test
Run deliberately failing tests with:
mix test --only failing_test