Property-Based Testing with PropEr, Erlang, and Elixir by Fred Hebert
Author:Fred Hebert
Language: eng
Format: epub, pdf
Tags: Pragmatic Bookshelf
Publisher: Pragmatic Bookshelf
Dividing with ?LETSHRINK
As you use PropEr, you may find yourself stuck with generators creating huge data structures that take a long time to shrink and often don’t give very interesting results back. This often happens when some very low-probability failure is triggered, meaning that the framework had to generate a lot of data to find it, and has limited chances of shrinking things in a significant manner.
Whenever that happens, the ?LETSHRINK([Pattern, ...], [Generator, ...], Expression) is what you need. In practice, we use the generator like this:
Erlang
?LETSHRINK([A,B,C], [list(number()), list(number()), list(number())],
A ++ B ++ C)
Elixir
let_shrink([
a <- list(number()),
b <- list(number()),
c <- list(number())
]) do
a ++ b ++ c
end
The macro looks a lot like a regular ?LET macro, but with a few constraints: the first two arguments must always be lists, and the third argument is an operation where all list elements get combined into one. Here, A, B, and C are three lists filled with integers, and A ++ B ++ C is just a bigger list of integers. The important part is that any of A, B or C can be used by the program instead of A ++ B ++ C.
The reason for that is that once a property fails and PropEr tries to shrink the data set, it will instead pick just one of A, B, or C without applying the transformation and return that directly. ?LETSHRINK is particularly appropriate for recursive structures, data made through branching, and all kinds of pieces of data that are generated by smashing others together and applying transformations, since taking a part of it is a legitimate way to get a simpler version.
Basically, we’re giving PropEr a way to divide the data up to isolate a failing subset more efficiently.
The most common form of ?LETSHRINK is the one you’d use on tree data structures. For a binary tree generator of size N, we’d write something like this:
Erlang code/Shrinking/erlang/pbt/test/prop_shrink.erl
tree(N) when N =< 1 ->
{leaf, number()};
tree(N) ->
PerBranch = N div 2,
{branch, tree(PerBranch), tree(PerBranch)}.
Elixir code/Shrinking/elixir/pbt/test/pbt_test.exs
def tree(n) when n <= 1 do
{:leaf, number()}
end
def tree(n) do
per_branch = div(n, 2)
{:branch, tree(per_branch), tree(per_branch)}
end
If you run sampleshrink/1 on it, you’ll find out that the elements within the tree shrink, but the tree itself stays the same size:
1> proper_gen:sampleshrink(prop_shrink:tree(4)).
{branch,{branch,{leaf,13},{leaf,0.6154862580810709}},
{branch,{leaf,8},{leaf,-3}}}
{branch,{branch,{leaf,0},{leaf,0.6154862580810709}},
{branch,{leaf,8},{leaf,-3}}}
{branch,{branch,{leaf,0},{leaf,-6}},{branch,{leaf,8},{leaf,-3}}}
{branch,{branch,{leaf,0},{leaf,0}},{branch,{leaf,8},{leaf,-3}}}
{branch,{branch,{leaf,0},{leaf,0}},{branch,{leaf,0},{leaf,-3}}}
{branch,{branch,{leaf,0},{leaf,0}},{branch,{leaf,0},{leaf,0}}}
Each of the trees in the sample contains exactly four entries: all the integers tend toward zero, but the structure itself has a fixed size. The obvious way to get the tree to shrink is through parameterizing it with the Size variable obtained from the ?SIZED(Var, Exp) macro. But if the failure requires internal tree elements to remain large while the tree structure itself is small, then the chances are fewer that shrinking by size only would work well.
Instead, if we use ?LETSHRINK, we can get a more shrink-friendly version:
Erlang code/Shrinking/erlang/pbt/test/prop_shrink.erl
tree_shrink(N) when N =< 1 ->
{leaf, number()};
tree_shrink(N)
Download
Property-Based Testing with PropEr, Erlang, and Elixir by Fred Hebert.pdf
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.
Coding Theory | Localization |
Logic | Object-Oriented Design |
Performance Optimization | Quality Control |
Reengineering | Robohelp |
Software Development | Software Reuse |
Structured Design | Testing |
Tools | UML |
Deep Learning with Python by François Chollet(11873)
Hello! Python by Anthony Briggs(9365)
OCA Java SE 8 Programmer I Certification Guide by Mala Gupta(9336)
The Mikado Method by Ola Ellnestam Daniel Brolund(9300)
Dependency Injection in .NET by Mark Seemann(8853)
Algorithms of the Intelligent Web by Haralambos Marmanis;Dmitry Babenko(7845)
Test-Driven iOS Development with Swift 4 by Dominik Hauser(7304)
Grails in Action by Glen Smith Peter Ledbrook(7291)
The Well-Grounded Java Developer by Benjamin J. Evans Martijn Verburg(7111)
Secrets of the JavaScript Ninja by John Resig Bear Bibeault(5951)
Kotlin in Action by Dmitry Jemerov(4633)
Practical Vim (for Kathryn Amaral) by Drew Neil(3724)
Cracking the GRE Premium Edition with 6 Practice Tests, 2015 (Graduate School Test Preparation) by Princeton Review(3590)
Linux Device Driver Development Cookbook by Rodolfo Giometti(3387)
Learn Windows PowerShell in a Month of Lunches by Don Jones(3236)
Learning Java by Patrick Niemeyer & Daniel Leuck(2867)
Learning React: Functional Web Development with React and Redux by Banks Alex & Porcello Eve(2830)
Becoming a Dynamics 365 Finance and Supply Chain Solution Architect by Brent Dawson(2574)
Mastering Java 9 by Dr. Edward Lavieri(2569)