valid inputs
properties of output
testing framework
Slide 15
Slide 15 text
github.com/whatyouhide/stream_data
Slide 16
Slide 16 text
example time:
sorting lists
Slide 17
Slide 17 text
test "sorting" do
assert sort([]) == []
assert sort([1, 2, 3]) == [1, 2, 3]
assert sort([2, 1, 3]) == [1, 2, 3]
end
Slide 18
Slide 18 text
lists of integers
Slide 19
Slide 19 text
it's a list
has the same elements
it's ordered
Slide 20
Slide 20 text
check all list <- list_of(int()) do
sorted = sort(list)
assert is_list(sorted)
assert same_elements?(list, sorted)
assert ordered?(sorted)
end
Slide 21
Slide 21 text
check all list <- list_of(int()) do
sorted = sort(list)
assert is_list(sorted)
assert same_elements?(list, sorted)
assert ordered?(sorted)
end
Slide 22
Slide 22 text
check all list <- list_of(int()) do
sorted = sort(list)
assert is_list(sorted)
assert same_elements?(list, sorted)
assert ordered?(sorted)
end
Slide 23
Slide 23 text
check all list <- list_of(int()) do
sorted = sort(list)
assert is_list(sorted)
assert same_elements?(list, sorted)
assert ordered?(sorted)
end
Slide 24
Slide 24 text
check all list <- list_of(int()) do
sorted = sort(list)
assert is_list(sorted)
assert same_elements?(list, sorted)
assert ordered?(sorted)
end
Slide 25
Slide 25 text
def sort(list), do: list
Slide 26
Slide 26 text
[32, 2, 44, -12]
[1, 0]
Slide 27
Slide 27 text
G E N E R A T O R S
Slide 28
Slide 28 text
iex> Enum.take(integer(), 4)
[1, 0, -3, 1]
Slide 29
Slide 29 text
Composability
Slide 30
Slide 30 text
number = one_of([integer(), float()])
Slide 31
Slide 31 text
StreamData.map(integer(), &abs/1)
Slide 32
Slide 32 text
def string(:ascii) do
integer(?\s..?~)
|> list_of()
|> map(&List.to_string/1)
end
Example
Slide 33
Slide 33 text
⚠
Keep shrinkability
Slide 34
Slide 34 text
constant(term)
bind_filter(gen, fun)
+
Slide 35
Slide 35 text
iex> Enum.take(constant(:foo), 4)
[:foo, :foo, :foo, :foo]
constant always generates a term
Slide 36
Slide 36 text
bind_filter(integer(), fn i ->
if i < 0 do
:skip
else
gen = map(list_of(integer()), &(&1 + i))
{:cont, gen}
end
end)
bind_filter (possibly) creates
generators from generated terms
Slide 37
Slide 37 text
P A T T E R N S
Slide 38
Slide 38 text
circular code
Slide 39
Slide 39 text
decode(encode(term)) == term
Slide 40
Slide 40 text
property "unicode escaping" do
check all string <- string(:printable) do
encoded = encode(string, escape: :unicode)
assert decode(encoded) == string
end
end
JSON encoding
Slide 41
Slide 41 text
oracle model
Slide 42
Slide 42 text
my_code() == oracle_code()
Slide 43
Slide 43 text
older system
less performant implementation
Slide 44
Slide 44 text
property "gives same results as Erlang impl" do
check all bin <- binary() do
assert Huffman.encode(bin) ==
:huffman.encode(bin)
end
end
https://www.youtube.com/watch?v=jvwfDdgg93E
property "only expected codes are returned" do
check all request <- request() do
response = HTTP.perform(request)
assert response.status in [200, 201, 400, 404]
end
end
Slide 48
Slide 48 text
locally , CI
Slide 49
Slide 49 text
if ci?() do
config :stream_data, max_runs: 500
else
config :stream_data, max_runs: 25
end
Slide 50
Slide 50 text
unit + properties
Slide 51
Slide 51 text
property "String.contains?/2" do
check all left <- string(),
right <- string() do
assert String.contains?(left <> right, left)
assert String.contains?(left <> right, right)
end
end
test "String.contains?/2" do
assert String.contains?("foobar", "foo")
assert String.contains?("foobar", "bar")
assert String.contains?("foobar", "ob")
end
+