An introduction to property based testing

Scott Wlaschin
Scott WlaschinF# trainer and consultant at FPbridge.co.uk
The lazy programmer's guide to
writing 1000's of tests
An introduction to property based testing
@ScottWlaschin
fsharpforfunandprofit.com
Part 1:
In which I have a conversation with a
remote developer
This was a project from a long time ago,
in a galaxy far far away
For some reason
we needed a
custom "add"
function
...some time later
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
So I decide to start writing the
unit tests myself
[<Test>]
let ``When I add 1 + 3, I expect 4``()=
let result = add 1 3
Assert.AreEqual(4,result)
[<Test>]
let ``When I add 2 + 2, I expect 4``()=
let result = add 2 2
Assert.AreEqual(4,result)


First, I had a look at the existing tests...
[<Test>]
let ``When I add -1 + 3, I expect 2``()=
let result = add -1 3
Assert.AreEqual(2,result) 
Ok, now for my first new test...
let add x y =
4
wtf!
Hmm.. let's look at the implementation...
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
[<Test>]
let ``When I add 2 + 3, I expect 5``()=
let result = add 2 3
Assert.AreEqual(5,result)
[<Test>]
let ``When I add 1 + 41, I expect 42``()=
let result = add 1 41
Assert.AreEqual(42,result)


Time for some more tests...
let add x y =
match (x,y) with
| (2,3) -> 5
| (1,41) -> 42
| (_,_) -> 4 // all other cases
Let's just check the implementation again...
An introduction to property based testing
An introduction to property based testing
An introduction to property based testing
Write the minimal code that will make the
test pass
At this point you need to write code that will
successfully pass the test.
The code written at this stage will not be 100%
final, you will improve it later stages.
Do not try to write the perfect code at this stage,
just write code that will pass the test.
From http://www.typemock.com/test-driven-development-tdd/
TDD best practices
[<Test>]
let ``When I add two numbers,
I expect to get their sum``()=
for (x,y,expected) in [
(1,2,3);
(2,2,4);
(3,5,8);
(27,15,42); ]
let actual = add x y
Assert.AreEqual(expected,actual)
Another attempt at a test

let add x y =
match (x,y) with
| (1,2) -> 3
| (2,3) -> 5
| (3,5) -> 8
| (1,41) -> 42
| (25,15) -> 42
| (_,_) -> 4 // all other cases
Let's check the implementation one more time....
It dawned on me who I was
dealing with...
...the legendary burned-out, always lazy and
often malicious programmer called...
The Enterprise
Developer From Hell
Rethinking the approach
The EDFH will always make
specific examples pass, no
matter what I do...
So let's not use
specific examples!
[<Test>]
let ``When I add two random numbers,
I expect their sum to be correct``()=
let x = randInt()
let y = randInt()
let expected = x + y
let actual = add x y
Assert.AreEqual(expected,actual)
Let's use random numbers instead...
[<Test>]
let ``When I add two random numbers (100 times),
I expect their sum to be correct``()=
for _ in [1..100] do
let x = randInt()
let y = randInt()
let expected = x + y
let actual = add x y
Assert.AreEqual(expected,actual)
Yea! Problem solved!
And why not do it 100 times just to be sure...
The EDFH can't beat this!
[<Test>]
let ``When I add two random numbers (100 times),
I expect their sum to be correct``()=
for _ in [1..100] do
let x = randInt()
let y = randInt()
let expected = x + y
let actual = add x y
Assert.AreEqual(expected,actual)
Uh-oh!
But if you can't test by using +, how CAN you test?
We can't test "add" using +!
Part II:
Property based testing
What are the "requirements" for
the "add" function?
It's hard to know where to get started, but one
approach is to compare it with something different...
How does "add" differ from "subtract", for example?
[<Test>]
let ``When I add two numbers, the result
should not depend on parameter order``()=
for _ in [1..100] do
let x = randInt()
let y = randInt()
let result1 = add x y
let result2 = add y x
Assert.AreEqual(result1,result2)
reversed params
So how does "add" differ from "subtract"?
For "subtract", the order of the parameters makes a
difference, while for "add" it doesn't.
let add x y =
x * y
The EDFH responds with:
TEST: ``When I add two numbers, the result
should not depend on parameter order``
Ok, what's the difference
between add and multiply?
Example: two "add 1"s is the same as one "add 2".
[<Test>]
let ``Adding 1 twice is the same as adding 2``()=
for _ in [1..100] do
let x = randInt()
let y = randInt()
let result1 = x |> add 1 |> add 1
let result2 = x |> add 2
Assert.AreEqual(result1,result2)
Test: two "add 1"s is the same as one "add 2".
let add x y =
x - y
The EDFH responds with:

TEST: ``When I add two numbers, the result
should not depend on parameter order``
TEST: ``Adding 1 twice is the same as adding 2``
Ha! Gotcha, EDFH!
But luckily we have the previous test as well!
let add x y =
0
The EDFH responds with another implementation:

TEST: ``When I add two numbers, the result
should not depend on parameter order``
TEST: ``Adding 1 twice is the same as adding 2``

Aarrghh! Where did our approach go wrong?
[<Test>]
let ``Adding zero is the same as doing nothing``()=
for _ in [1..100] do
let x = randInt()
let result1 = x |> add 0
let result2 = x
Assert.AreEqual(result1,result2)
Yes! Adding zero is the same as doing nothing
We have to check that the result is somehow connected to the input.
Is there a trivial property of add that we know the answer to
without reimplementing our own version?
Finally, the EDFH is defeated...

TEST: ``When I add two numbers, the result
should not depend on parameter order``
TEST: ``Adding 1 twice is the same as adding 2``

TEST: ``Adding zero is the same as doing nothing``

If these are all true we
MUST have a correct
implementation*
* not quite true
Refactoring
let propertyCheck property =
// property has type: int -> int -> bool
for _ in [1..100] do
let x = randInt()
let y = randInt()
let result = property x y
Assert.IsTrue(result)
Let's extract the shared code... Pass in a "property"
Check the property is
true for random inputs
let commutativeProperty x y =
let result1 = add x y
let result2 = add y x
result1 = result2
And the tests now look like:
[<Test>]
let ``When I add two numbers, the result
should not depend on parameter order``()=
propertyCheck commutativeProperty
let adding1TwiceIsAdding2OnceProperty x _ =
let result1 = x |> add 1 |> add 1
let result2 = x |> add 2
result1 = result2
And the second property
[<Test>]
let ``Adding 1 twice is the same as adding 2``()=
propertyCheck adding1TwiceIsAdding2OnceProperty
let identityProperty x _ =
let result1 = x |> add 0
result1 = x
And the third property
[<Test>]
let ``Adding zero is the same as doing nothing``()=
propertyCheck identityProperty
Review
Testing with properties
• The parameter order doesn't matter
• Doing "add 1" twice is the same as
doing "add 2" once
• Adding zero does nothing
These properties
apply to ALL inputs
So we have a very
high confidence that
the implementation is
correct
Testing with properties
• "Commutativity" property
• "Associativity" property
• "Identity" property
These properties
define addition!
The EDFH can't create an
incorrect implementation!
Bonus: By using specifications, we have
understood the requirements in a deeper way.
Specification
Why bother with the EDFH?
Surely such a malicious programmer is
unrealistic and over-the-top?
Evil
Stupid
Lazy
In practice,
no difference!
In my career, I've always had to deal with one
stupid person in particular 
Me!
When I look at my old code, I almost always see something wrong!
I've often created flawed implementations, not out of evil
intent, but out of unawareness and blindness
The real EDFH!
Part III:
QuickCheck and its ilk
Wouldn't it be nice to have a toolkit for doing this?
The "QuickCheck" library was originally developed for Haskell by
Koen Claessen and John Hughes, and has been ported to many
other languages.
QuickCheck
Generator Shrinker
Your Property Function that returns bool
Checker API
Pass to checker
Generates
random inputs
Creates minimal
failing input
// correct implementation of add!
let add x y = x + y
let commutativeProperty x y =
let result1 = add x y
let result2 = add y x
result1 = result2
// check the property interactively
Check.Quick commutativeProperty
Using QuickCheck (FsCheck) looks like this:
Ok, passed 100 tests.
And get the output:
Generators:
making random inputs
QuickCheck
Generator Shrinker
Checker API
Generates ints
"int" generator 0, 1, 3, -2, ... etc
Generates strings
"string" generator "", "eiX$a^", "U%0Ika&r", ... etc
"bool" generator true, false, false, true, ... etc
Generating primitive types
Generates bools
Generates pairs of ints
"int*int" generator (0,0), (1,0), (2,0), (-1,1), (-1,2) ... etc
Generates options
"int option" generator Some 0, Some -1, None, Some -4; None ...
"Color" generator Green 47, Red, Blue true, Green -12, ...
Generating compound types
type Color = Red | Green of int | Blue of bool
Generates values of custom type
Define custom type
let commutativeProperty (x,y) =
let result1 = add x y
let result2 = add y x // reversed params
result1 = result2
(b) Appropriate generator will
be automatically created
int*int generator
(0,0) (1,0) (2,0) (-1,1) (100,-99) ...
(a) Checker detects that the
input is a pair of ints
Checker API
(c) Valid values will be generated...
(d) ...and passed to
the property for
evaluation
How it works in practice
Shrinking:
dealing with failure
QuickCheck
Generator Shrinker
Checker API
let smallerThan81Property x =
x < 81
Property to test – we know it's gonna fail!
"int" generator 0, 1, 3, -2, 34, -65, 100
Fails at 100!
So 100 fails, but knowing that is not very helpful
How shrinking works
Time to start shrinking!
let smallerThan81Property x =
x < 81
Shrink again starting at 88
How shrinking works
Shrink list for 100 0, 50, 75, 88, 94, 97, 99
Fails at 88!
Generate a new
sequence up to 100
let smallerThan81Property x =
x < 81
Shrink again starting at 83
How shrinking works
Shrink list for 88 0, 44, 66, 77, 83, 86, 87
Fails at 83!
Generate a new
sequence up to 88
let smallerThan81Property x =
x < 81
Shrink again starting at 81
How shrinking works
Shrink list for 83 0, 42, 63, 73, 78, 81, 82
Fails at 81!
Generate a new
sequence up to 83
let smallerThan81Property x =
x < 81
Shrink has determined that 81 is
the smallest failing input!
How shrinking works
Shrink list for 81 0, 41, 61, 71, 76, 79, 80
All pass!
Generate a new
sequence up to 81
Shrinking – final result
Check.Quick smallerThan81Property
// result: Falsifiable, after 23 tests (3 shrinks)
// 81
Shrinking is really helpful to show
the boundaries where errors happen
Shrinking is built into the check:
Part IV:
How to choose properties
ABC
123
do X do X
do Y
do Y
"Different paths, same destination"
Examples:
- Commutivity
- Associativity
- Map
- Monad & Functor laws
"Different paths, same destination"
Applied to a sort function
[1;2;3]
?
do ? do ?
List.sort
List.sort
"Different paths, same destination"
Applied to a sort function
[2;3;1]
[-2;-3;-1] [-3;-2;-1]
[1;2;3]
Negate
List.sort
List.sort
Negate
then reverse
"Different paths, same destination"
Applied to a map function
Some(2)
.Map(x => x * 3)
Some(2 * 3)
x
Option (x) Option (f x)
f x
Create
Map f
f
Create
f x = x * 3
"There and back again"
ABC 100101001
Do X
Inverse
Examples:
- Serialization/Deserialization
- Addition/Subtraction
-Write/Read
- SetProperty/GetProperty
"There and back again"
Applied to a list reverse function
[1;2;3] [3;2;1]
reverse
reverse
"Some things never change"
 
transform
Examples:
- Size of a collection
- Contents of a collection
- Balanced trees
[2;3;1]
[-2;-3;-1] [-3;-2;-1]
[1;2;3]
Negate
List.sort
List.sort
Negate
then reverse
The EDFH and List.Sort
The EDFH can beat this!
The EDFH and List.Sort
[2;3;1]
[-2;-3;-1] [ ]
[ ]
Negate
List.evilSort
List.evilSort
Negate
then reverse
EvilSort just returns an empty list!
This passes the "commutivity" test!
"Some things never change"
[2;3;1]
[1; 2; 3]; [2; 1; 3]; [2; 3; 1];
[1; 3; 2]; [3; 1; 2]; [3; 2; 1]
[1;2;3]
List.sort
Must be one of these
permutations
Used to ensure the sort function is good
"The more things change,
the more they stay the same"
 
distinct

distinct
Idempotence:
- Sort
- Filter
- Event processing
- Required for distributed designs
"Solve a smaller problem first"
     
- Divide and conquer algorithms (e.g. quicksort)
- Structural induction (recursive data structures)
"Hard to prove, easy to verify"
- Prime number factorization
-Too many others to mention!
"Hard to prove, easy to verify"
Applied to a tokenizer
“a,b,c”
split
“a” “b” “c”
“a,b,c”
Combine and
verify
To verify the tokenizer, just check that the
concatenated tokens give us back the original string
"Hard to prove, easy to verify"
Applied to a sort
To verify the sort,
check that each pair is ordered
[2;3;1]
(1<=2) (2<=3)
[1;2;3]
List.sort
ABC
ABC 123
123
Compare
System
under test
Test Oracle
"The test oracle"
- Compare optimized with slow brute-force version
- Compare parallel with single thread version.
PartV:
Model based testing
Using the test oracle approach
for complex implementations
Testing a simple database
Open Incr Close Incr Open Close
Open Decr Open
Four operations: Open, Close, Increment, Decrement
How do we know that our db works?
Let QuickCheck generate a random list of these actions for each client
Open Incr
Client
A
Client
B
Two clients: Client A and Client B
Testing a simple database
Compare model result with real system!
Open Incr Close Incr Open Close
Open Decr Open Open Incr
Test on real
system
Open Incr Close Incr Open Close
Open Decr Open Open Incr
Test on very
simple model1 00 0 1
(just an in-memory
accumulator)Connection closed,
so no change
Real world example
• Subtle bugs in an Erlang module
• The steps to reproduce were bizarre
– open-close-open file then exactly 3 parallel ops
– no human would ever think to write this test case
• Shrinker critical in finding minimal sequence
• War stories from John Hughes at
https://vimeo.com/68383317
Example-based tests vs.
Property-based tests
Example-based tests vs. Property-based tests
• PBTs are more general
– One property-based test can replace many example-
based tests.
• PBTs can reveal overlooked edge cases
– Nulls, negative numbers, weird strings, etc.
• PBTs ensure deep understanding of requirements
– Property-based tests force you to think! 
• Example-based tests are still helpful though!
– Easier to understand for newcomers
Summary
Be lazy! Don't write tests, generate them!
Use property-based thinking to gain
deeper insight into the requirements
The lazy programmer's guide to
writing 1000's of tests
An introduction to property based testing
Let us know if you
need help with F#
Thanks!
@ScottWlaschin
fsharpforfunandprofit.com/pbt
fsharpworks.com Slides and video here
Contact me
1 of 97

Recommended

The lazy programmer's guide to writing thousands of tests by
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsScott Wlaschin
911 views105 slides
Domain Modeling in a Functional World by
Domain Modeling in a Functional WorldDomain Modeling in a Functional World
Domain Modeling in a Functional WorldDebasish Ghosh
50.6K views88 slides
The Functional Programming Toolkit (NDC Oslo 2019) by
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)Scott Wlaschin
6.3K views261 slides
The Power of Composition by
The Power of CompositionThe Power of Composition
The Power of CompositionScott Wlaschin
7.2K views165 slides
Functional solid by
Functional solidFunctional solid
Functional solidMatt Stine
2.7K views131 slides
The Power of Composition (NDC Oslo 2020) by
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)Scott Wlaschin
2.2K views191 slides

More Related Content

What's hot

Boost your productivity with Scala tooling! by
Boost your productivity  with Scala tooling!Boost your productivity  with Scala tooling!
Boost your productivity with Scala tooling!MeriamLachkar1
210 views49 slides
Deep dive into Xtext scoping local and global scopes explained by
Deep dive into Xtext scoping local and global scopes explainedDeep dive into Xtext scoping local and global scopes explained
Deep dive into Xtext scoping local and global scopes explainedHolger Schill
3.4K views74 slides
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1 by
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Philip Schwarz
1.9K views33 slides
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2 by
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Philip Schwarz
1.3K views77 slides
Thirteen ways of looking at a turtle by
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtleScott Wlaschin
8.2K views121 slides
Domain Modeling with FP (DDD Europe 2020) by
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Scott Wlaschin
1.5K views95 slides

What's hot(20)

Boost your productivity with Scala tooling! by MeriamLachkar1
Boost your productivity  with Scala tooling!Boost your productivity  with Scala tooling!
Boost your productivity with Scala tooling!
MeriamLachkar1210 views
Deep dive into Xtext scoping local and global scopes explained by Holger Schill
Deep dive into Xtext scoping local and global scopes explainedDeep dive into Xtext scoping local and global scopes explained
Deep dive into Xtext scoping local and global scopes explained
Holger Schill3.4K views
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1 by Philip Schwarz
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Philip Schwarz1.9K views
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2 by Philip Schwarz
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Philip Schwarz1.3K views
Thirteen ways of looking at a turtle by Scott Wlaschin
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
Scott Wlaschin8.2K views
Domain Modeling with FP (DDD Europe 2020) by Scott Wlaschin
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
Scott Wlaschin1.5K views
[C++ korea] Effective Modern C++ 신촌 Study Item20,21,23 by Seok-joon Yun
[C++ korea] Effective Modern C++ 신촌 Study Item20,21,23[C++ korea] Effective Modern C++ 신촌 Study Item20,21,23
[C++ korea] Effective Modern C++ 신촌 Study Item20,21,23
Seok-joon Yun1.5K views
Property-Based Testing by Shai Geva
Property-Based TestingProperty-Based Testing
Property-Based Testing
Shai Geva314 views
Lightweight Xtext Editors as SWT Widgets by meysholdt
Lightweight Xtext Editors as SWT WidgetsLightweight Xtext Editors as SWT Widgets
Lightweight Xtext Editors as SWT Widgets
meysholdt3.7K views
How to choose best containers in STL (C++) by Sangharsh agarwal
How to choose best containers in STL (C++)How to choose best containers in STL (C++)
How to choose best containers in STL (C++)
Sangharsh agarwal13.3K views
Dependency injection - the right way by Thibaud Desodt
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right way
Thibaud Desodt23.1K views
Objetos Pythonicos - compacto by Luciano Ramalho
Objetos Pythonicos - compactoObjetos Pythonicos - compacto
Objetos Pythonicos - compacto
Luciano Ramalho2.6K views
Stacks,queues,linked-list by pinakspatel
Stacks,queues,linked-listStacks,queues,linked-list
Stacks,queues,linked-list
pinakspatel1.6K views
ClojurianからみたElixir by Kent Ohashi
ClojurianからみたElixirClojurianからみたElixir
ClojurianからみたElixir
Kent Ohashi2.3K views
The Proxy Fairy, and The Magic of Spring Framework by Victor Rentea
The Proxy Fairy, and The Magic of Spring FrameworkThe Proxy Fairy, and The Magic of Spring Framework
The Proxy Fairy, and The Magic of Spring Framework
Victor Rentea1.3K views
Http4s, Doobie and Circe: The Functional Web Stack by GaryCoady
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady6.3K views
What is Range Function? | Range in Python Explained | Edureka by Edureka!
What is Range Function? | Range in Python Explained | EdurekaWhat is Range Function? | Range in Python Explained | Edureka
What is Range Function? | Range in Python Explained | Edureka
Edureka!600 views
Purely Functional Data Structures in Scala by Vladimir Kostyukov
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in Scala
Vladimir Kostyukov52.7K views

Similar to An introduction to property based testing

關於測試,我說的其實是...... by
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......hugo lu
8.6K views135 slides
An Introduction to Test Driven Development with React by
An Introduction to Test Driven Development with ReactAn Introduction to Test Driven Development with React
An Introduction to Test Driven Development with ReactFITC
452 views37 slides
Functional Programming with Groovy by
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
13.4K views71 slides
Tdd pecha kucha_v2 by
Tdd pecha kucha_v2Tdd pecha kucha_v2
Tdd pecha kucha_v2Paul Boos
903 views36 slides
Test Driven Development by
Test Driven DevelopmentTest Driven Development
Test Driven DevelopmentSheeju Alex
497 views23 slides
Testing in Python: doctest and unittest (Updated) by
Testing in Python: doctest and unittest (Updated)Testing in Python: doctest and unittest (Updated)
Testing in Python: doctest and unittest (Updated)Fariz Darari
381 views33 slides

Similar to An introduction to property based testing(20)

關於測試,我說的其實是...... by hugo lu
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......
hugo lu8.6K views
An Introduction to Test Driven Development with React by FITC
An Introduction to Test Driven Development with ReactAn Introduction to Test Driven Development with React
An Introduction to Test Driven Development with React
FITC452 views
Functional Programming with Groovy by Arturo Herrero
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
Arturo Herrero13.4K views
Tdd pecha kucha_v2 by Paul Boos
Tdd pecha kucha_v2Tdd pecha kucha_v2
Tdd pecha kucha_v2
Paul Boos903 views
Test Driven Development by Sheeju Alex
Test Driven DevelopmentTest Driven Development
Test Driven Development
Sheeju Alex497 views
Testing in Python: doctest and unittest (Updated) by Fariz Darari
Testing in Python: doctest and unittest (Updated)Testing in Python: doctest and unittest (Updated)
Testing in Python: doctest and unittest (Updated)
Fariz Darari381 views
Testing in Python: doctest and unittest by Fariz Darari
Testing in Python: doctest and unittestTesting in Python: doctest and unittest
Testing in Python: doctest and unittest
Fariz Darari555 views
STAMP Descartes Presentation by STAMP Project
STAMP Descartes PresentationSTAMP Descartes Presentation
STAMP Descartes Presentation
STAMP Project103 views
Testing in Django by Kevin Harvey
Testing in DjangoTesting in Django
Testing in Django
Kevin Harvey2.5K views
Python_Cheat_Sheet_Keywords_1664634397.pdf by sagar414433
Python_Cheat_Sheet_Keywords_1664634397.pdfPython_Cheat_Sheet_Keywords_1664634397.pdf
Python_Cheat_Sheet_Keywords_1664634397.pdf
sagar41443323 views
Python_Cheat_Sheet_Keywords_1664634397.pdf by sagar414433
Python_Cheat_Sheet_Keywords_1664634397.pdfPython_Cheat_Sheet_Keywords_1664634397.pdf
Python_Cheat_Sheet_Keywords_1664634397.pdf
sagar41443364 views
Unit/Integration Testing using Spock by Anuj Aneja
Unit/Integration Testing using SpockUnit/Integration Testing using Spock
Unit/Integration Testing using Spock
Anuj Aneja493 views
Tdd for BT E2E test community by Kerry Buckley
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test community
Kerry Buckley1.2K views
Mutation Testing - Ruby Edition by Chris Sinjakli
Mutation Testing - Ruby EditionMutation Testing - Ruby Edition
Mutation Testing - Ruby Edition
Chris Sinjakli1.6K views

More from Scott Wlaschin

Domain Modeling Made Functional (DevTernity 2022) by
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Scott Wlaschin
1.9K views136 slides
Pipeline oriented programming by
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programmingScott Wlaschin
8.2K views102 slides
Building confidence in concurrent code with a model checker: TLA+ for program... by
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Scott Wlaschin
2K views159 slides
Reinventing the Transaction Script (NDC London 2020) by
Reinventing the Transaction Script (NDC London 2020)Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)Scott Wlaschin
2.1K views138 slides
The Functional Programmer's Toolkit (NDC London 2019) by
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)Scott Wlaschin
1.9K views224 slides
The Power Of Composition (DotNext 2019) by
The Power Of Composition (DotNext 2019)The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)Scott Wlaschin
1.9K views184 slides

More from Scott Wlaschin(20)

Domain Modeling Made Functional (DevTernity 2022) by Scott Wlaschin
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)
Scott Wlaschin1.9K views
Pipeline oriented programming by Scott Wlaschin
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
Scott Wlaschin8.2K views
Building confidence in concurrent code with a model checker: TLA+ for program... by Scott Wlaschin
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...
Scott Wlaschin2K views
Reinventing the Transaction Script (NDC London 2020) by Scott Wlaschin
Reinventing the Transaction Script (NDC London 2020)Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)
Scott Wlaschin2.1K views
The Functional Programmer's Toolkit (NDC London 2019) by Scott Wlaschin
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
Scott Wlaschin1.9K views
The Power Of Composition (DotNext 2019) by Scott Wlaschin
The Power Of Composition (DotNext 2019)The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)
Scott Wlaschin1.9K views
Domain Modeling Made Functional (KanDDDinsky 2019) by Scott Wlaschin
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
Scott Wlaschin3K views
Four Languages From Forty Years Ago (NewCrafts 2019) by Scott Wlaschin
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)
Scott Wlaschin2.1K views
Functional Design Patterns (DevTernity 2018) by Scott Wlaschin
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
Scott Wlaschin5.5K views
Four Languages From Forty Years Ago by Scott Wlaschin
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years Ago
Scott Wlaschin10.2K views
Designing with capabilities (DDD-EU 2017) by Scott Wlaschin
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)
Scott Wlaschin8.1K views
Designing with Capabilities by Scott Wlaschin
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
Scott Wlaschin13.5K views
Dr Frankenfunctor and the Monadster by Scott Wlaschin
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
Scott Wlaschin20.5K views
Enterprise Tic-Tac-Toe by Scott Wlaschin
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
Scott Wlaschin15.1K views
Functional Programming Patterns (BuildStuff '14) by Scott Wlaschin
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
Scott Wlaschin175.3K views
Domain Driven Design with the F# type System -- F#unctional Londoners 2014 by Scott Wlaschin
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Scott Wlaschin171.6K views
Railway Oriented Programming by Scott Wlaschin
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
Scott Wlaschin639K views

Recently uploaded

360 graden fabriek by
360 graden fabriek360 graden fabriek
360 graden fabriekinfo33492
36 views25 slides
Software testing company in India.pptx by
Software testing company in India.pptxSoftware testing company in India.pptx
Software testing company in India.pptxSakshiPatel82
7 views9 slides
Agile 101 by
Agile 101Agile 101
Agile 101John Valentino
6 views20 slides
Headless JS UG Presentation.pptx by
Headless JS UG Presentation.pptxHeadless JS UG Presentation.pptx
Headless JS UG Presentation.pptxJack Spektor
7 views24 slides
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium... by
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...Lisi Hocke
28 views124 slides
Copilot Prompting Toolkit_All Resources.pdf by
Copilot Prompting Toolkit_All Resources.pdfCopilot Prompting Toolkit_All Resources.pdf
Copilot Prompting Toolkit_All Resources.pdfRiccardo Zamana
8 views4 slides

Recently uploaded(20)

360 graden fabriek by info33492
360 graden fabriek360 graden fabriek
360 graden fabriek
info3349236 views
Software testing company in India.pptx by SakshiPatel82
Software testing company in India.pptxSoftware testing company in India.pptx
Software testing company in India.pptx
SakshiPatel827 views
Headless JS UG Presentation.pptx by Jack Spektor
Headless JS UG Presentation.pptxHeadless JS UG Presentation.pptx
Headless JS UG Presentation.pptx
Jack Spektor7 views
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium... by Lisi Hocke
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Lisi Hocke28 views
Copilot Prompting Toolkit_All Resources.pdf by Riccardo Zamana
Copilot Prompting Toolkit_All Resources.pdfCopilot Prompting Toolkit_All Resources.pdf
Copilot Prompting Toolkit_All Resources.pdf
Riccardo Zamana8 views
AI and Ml presentation .pptx by FayazAli87
AI and Ml presentation .pptxAI and Ml presentation .pptx
AI and Ml presentation .pptx
FayazAli8711 views
A first look at MariaDB 11.x features and ideas on how to use them by Federico Razzoli
A first look at MariaDB 11.x features and ideas on how to use themA first look at MariaDB 11.x features and ideas on how to use them
A first look at MariaDB 11.x features and ideas on how to use them
Federico Razzoli45 views
Advanced API Mocking Techniques by Dimpy Adhikary
Advanced API Mocking TechniquesAdvanced API Mocking Techniques
Advanced API Mocking Techniques
Dimpy Adhikary19 views
Tridens DevOps by Tridens
Tridens DevOpsTridens DevOps
Tridens DevOps
Tridens9 views
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -... by Deltares
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
Deltares6 views
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge... by Deltares
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
Deltares17 views
Generic or specific? Making sensible software design decisions by Bert Jan Schrijver
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J... by Deltares
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...
Deltares9 views
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko... by Deltares
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
Deltares12 views
DSD-INT 2023 Salt intrusion Modelling of the Lauwersmeer, towards a measureme... by Deltares
DSD-INT 2023 Salt intrusion Modelling of the Lauwersmeer, towards a measureme...DSD-INT 2023 Salt intrusion Modelling of the Lauwersmeer, towards a measureme...
DSD-INT 2023 Salt intrusion Modelling of the Lauwersmeer, towards a measureme...
Deltares5 views
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ... by Deltares
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
Deltares10 views
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action by Márton Kodok
Gen Apps on Google Cloud PaLM2 and Codey APIs in ActionGen Apps on Google Cloud PaLM2 and Codey APIs in Action
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action
Márton Kodok5 views

An introduction to property based testing

  • 1. The lazy programmer's guide to writing 1000's of tests An introduction to property based testing @ScottWlaschin fsharpforfunandprofit.com
  • 2. Part 1: In which I have a conversation with a remote developer This was a project from a long time ago, in a galaxy far far away
  • 3. For some reason we needed a custom "add" function
  • 17. So I decide to start writing the unit tests myself
  • 18. [<Test>] let ``When I add 1 + 3, I expect 4``()= let result = add 1 3 Assert.AreEqual(4,result) [<Test>] let ``When I add 2 + 2, I expect 4``()= let result = add 2 2 Assert.AreEqual(4,result)   First, I had a look at the existing tests...
  • 19. [<Test>] let ``When I add -1 + 3, I expect 2``()= let result = add -1 3 Assert.AreEqual(2,result)  Ok, now for my first new test...
  • 20. let add x y = 4 wtf! Hmm.. let's look at the implementation...
  • 24. [<Test>] let ``When I add 2 + 3, I expect 5``()= let result = add 2 3 Assert.AreEqual(5,result) [<Test>] let ``When I add 1 + 41, I expect 42``()= let result = add 1 41 Assert.AreEqual(42,result)   Time for some more tests...
  • 25. let add x y = match (x,y) with | (2,3) -> 5 | (1,41) -> 42 | (_,_) -> 4 // all other cases Let's just check the implementation again...
  • 29. Write the minimal code that will make the test pass At this point you need to write code that will successfully pass the test. The code written at this stage will not be 100% final, you will improve it later stages. Do not try to write the perfect code at this stage, just write code that will pass the test. From http://www.typemock.com/test-driven-development-tdd/ TDD best practices
  • 30. [<Test>] let ``When I add two numbers, I expect to get their sum``()= for (x,y,expected) in [ (1,2,3); (2,2,4); (3,5,8); (27,15,42); ] let actual = add x y Assert.AreEqual(expected,actual) Another attempt at a test 
  • 31. let add x y = match (x,y) with | (1,2) -> 3 | (2,3) -> 5 | (3,5) -> 8 | (1,41) -> 42 | (25,15) -> 42 | (_,_) -> 4 // all other cases Let's check the implementation one more time....
  • 32. It dawned on me who I was dealing with... ...the legendary burned-out, always lazy and often malicious programmer called...
  • 34. Rethinking the approach The EDFH will always make specific examples pass, no matter what I do... So let's not use specific examples!
  • 35. [<Test>] let ``When I add two random numbers, I expect their sum to be correct``()= let x = randInt() let y = randInt() let expected = x + y let actual = add x y Assert.AreEqual(expected,actual) Let's use random numbers instead...
  • 36. [<Test>] let ``When I add two random numbers (100 times), I expect their sum to be correct``()= for _ in [1..100] do let x = randInt() let y = randInt() let expected = x + y let actual = add x y Assert.AreEqual(expected,actual) Yea! Problem solved! And why not do it 100 times just to be sure... The EDFH can't beat this!
  • 37. [<Test>] let ``When I add two random numbers (100 times), I expect their sum to be correct``()= for _ in [1..100] do let x = randInt() let y = randInt() let expected = x + y let actual = add x y Assert.AreEqual(expected,actual) Uh-oh! But if you can't test by using +, how CAN you test? We can't test "add" using +!
  • 39. What are the "requirements" for the "add" function? It's hard to know where to get started, but one approach is to compare it with something different... How does "add" differ from "subtract", for example?
  • 40. [<Test>] let ``When I add two numbers, the result should not depend on parameter order``()= for _ in [1..100] do let x = randInt() let y = randInt() let result1 = add x y let result2 = add y x Assert.AreEqual(result1,result2) reversed params So how does "add" differ from "subtract"? For "subtract", the order of the parameters makes a difference, while for "add" it doesn't.
  • 41. let add x y = x * y The EDFH responds with: TEST: ``When I add two numbers, the result should not depend on parameter order``
  • 42. Ok, what's the difference between add and multiply? Example: two "add 1"s is the same as one "add 2".
  • 43. [<Test>] let ``Adding 1 twice is the same as adding 2``()= for _ in [1..100] do let x = randInt() let y = randInt() let result1 = x |> add 1 |> add 1 let result2 = x |> add 2 Assert.AreEqual(result1,result2) Test: two "add 1"s is the same as one "add 2".
  • 44. let add x y = x - y The EDFH responds with:  TEST: ``When I add two numbers, the result should not depend on parameter order`` TEST: ``Adding 1 twice is the same as adding 2`` Ha! Gotcha, EDFH! But luckily we have the previous test as well!
  • 45. let add x y = 0 The EDFH responds with another implementation:  TEST: ``When I add two numbers, the result should not depend on parameter order`` TEST: ``Adding 1 twice is the same as adding 2``  Aarrghh! Where did our approach go wrong?
  • 46. [<Test>] let ``Adding zero is the same as doing nothing``()= for _ in [1..100] do let x = randInt() let result1 = x |> add 0 let result2 = x Assert.AreEqual(result1,result2) Yes! Adding zero is the same as doing nothing We have to check that the result is somehow connected to the input. Is there a trivial property of add that we know the answer to without reimplementing our own version?
  • 47. Finally, the EDFH is defeated...  TEST: ``When I add two numbers, the result should not depend on parameter order`` TEST: ``Adding 1 twice is the same as adding 2``  TEST: ``Adding zero is the same as doing nothing``  If these are all true we MUST have a correct implementation* * not quite true
  • 49. let propertyCheck property = // property has type: int -> int -> bool for _ in [1..100] do let x = randInt() let y = randInt() let result = property x y Assert.IsTrue(result) Let's extract the shared code... Pass in a "property" Check the property is true for random inputs
  • 50. let commutativeProperty x y = let result1 = add x y let result2 = add y x result1 = result2 And the tests now look like: [<Test>] let ``When I add two numbers, the result should not depend on parameter order``()= propertyCheck commutativeProperty
  • 51. let adding1TwiceIsAdding2OnceProperty x _ = let result1 = x |> add 1 |> add 1 let result2 = x |> add 2 result1 = result2 And the second property [<Test>] let ``Adding 1 twice is the same as adding 2``()= propertyCheck adding1TwiceIsAdding2OnceProperty
  • 52. let identityProperty x _ = let result1 = x |> add 0 result1 = x And the third property [<Test>] let ``Adding zero is the same as doing nothing``()= propertyCheck identityProperty
  • 54. Testing with properties • The parameter order doesn't matter • Doing "add 1" twice is the same as doing "add 2" once • Adding zero does nothing These properties apply to ALL inputs So we have a very high confidence that the implementation is correct
  • 55. Testing with properties • "Commutativity" property • "Associativity" property • "Identity" property These properties define addition! The EDFH can't create an incorrect implementation! Bonus: By using specifications, we have understood the requirements in a deeper way. Specification
  • 56. Why bother with the EDFH? Surely such a malicious programmer is unrealistic and over-the-top?
  • 58. In my career, I've always had to deal with one stupid person in particular  Me! When I look at my old code, I almost always see something wrong! I've often created flawed implementations, not out of evil intent, but out of unawareness and blindness The real EDFH!
  • 59. Part III: QuickCheck and its ilk Wouldn't it be nice to have a toolkit for doing this? The "QuickCheck" library was originally developed for Haskell by Koen Claessen and John Hughes, and has been ported to many other languages.
  • 60. QuickCheck Generator Shrinker Your Property Function that returns bool Checker API Pass to checker Generates random inputs Creates minimal failing input
  • 61. // correct implementation of add! let add x y = x + y let commutativeProperty x y = let result1 = add x y let result2 = add y x result1 = result2 // check the property interactively Check.Quick commutativeProperty Using QuickCheck (FsCheck) looks like this: Ok, passed 100 tests. And get the output:
  • 63. Generates ints "int" generator 0, 1, 3, -2, ... etc Generates strings "string" generator "", "eiX$a^", "U%0Ika&r", ... etc "bool" generator true, false, false, true, ... etc Generating primitive types Generates bools
  • 64. Generates pairs of ints "int*int" generator (0,0), (1,0), (2,0), (-1,1), (-1,2) ... etc Generates options "int option" generator Some 0, Some -1, None, Some -4; None ... "Color" generator Green 47, Red, Blue true, Green -12, ... Generating compound types type Color = Red | Green of int | Blue of bool Generates values of custom type Define custom type
  • 65. let commutativeProperty (x,y) = let result1 = add x y let result2 = add y x // reversed params result1 = result2 (b) Appropriate generator will be automatically created int*int generator (0,0) (1,0) (2,0) (-1,1) (100,-99) ... (a) Checker detects that the input is a pair of ints Checker API (c) Valid values will be generated... (d) ...and passed to the property for evaluation How it works in practice
  • 67. let smallerThan81Property x = x < 81 Property to test – we know it's gonna fail! "int" generator 0, 1, 3, -2, 34, -65, 100 Fails at 100! So 100 fails, but knowing that is not very helpful How shrinking works Time to start shrinking!
  • 68. let smallerThan81Property x = x < 81 Shrink again starting at 88 How shrinking works Shrink list for 100 0, 50, 75, 88, 94, 97, 99 Fails at 88! Generate a new sequence up to 100
  • 69. let smallerThan81Property x = x < 81 Shrink again starting at 83 How shrinking works Shrink list for 88 0, 44, 66, 77, 83, 86, 87 Fails at 83! Generate a new sequence up to 88
  • 70. let smallerThan81Property x = x < 81 Shrink again starting at 81 How shrinking works Shrink list for 83 0, 42, 63, 73, 78, 81, 82 Fails at 81! Generate a new sequence up to 83
  • 71. let smallerThan81Property x = x < 81 Shrink has determined that 81 is the smallest failing input! How shrinking works Shrink list for 81 0, 41, 61, 71, 76, 79, 80 All pass! Generate a new sequence up to 81
  • 72. Shrinking – final result Check.Quick smallerThan81Property // result: Falsifiable, after 23 tests (3 shrinks) // 81 Shrinking is really helpful to show the boundaries where errors happen Shrinking is built into the check:
  • 73. Part IV: How to choose properties
  • 74. ABC 123 do X do X do Y do Y "Different paths, same destination" Examples: - Commutivity - Associativity - Map - Monad & Functor laws
  • 75. "Different paths, same destination" Applied to a sort function [1;2;3] ? do ? do ? List.sort List.sort
  • 76. "Different paths, same destination" Applied to a sort function [2;3;1] [-2;-3;-1] [-3;-2;-1] [1;2;3] Negate List.sort List.sort Negate then reverse
  • 77. "Different paths, same destination" Applied to a map function Some(2) .Map(x => x * 3) Some(2 * 3) x Option (x) Option (f x) f x Create Map f f Create f x = x * 3
  • 78. "There and back again" ABC 100101001 Do X Inverse Examples: - Serialization/Deserialization - Addition/Subtraction -Write/Read - SetProperty/GetProperty
  • 79. "There and back again" Applied to a list reverse function [1;2;3] [3;2;1] reverse reverse
  • 80. "Some things never change"   transform Examples: - Size of a collection - Contents of a collection - Balanced trees
  • 82. The EDFH and List.Sort [2;3;1] [-2;-3;-1] [ ] [ ] Negate List.evilSort List.evilSort Negate then reverse EvilSort just returns an empty list! This passes the "commutivity" test!
  • 83. "Some things never change" [2;3;1] [1; 2; 3]; [2; 1; 3]; [2; 3; 1]; [1; 3; 2]; [3; 1; 2]; [3; 2; 1] [1;2;3] List.sort Must be one of these permutations Used to ensure the sort function is good
  • 84. "The more things change, the more they stay the same"   distinct  distinct Idempotence: - Sort - Filter - Event processing - Required for distributed designs
  • 85. "Solve a smaller problem first"       - Divide and conquer algorithms (e.g. quicksort) - Structural induction (recursive data structures)
  • 86. "Hard to prove, easy to verify" - Prime number factorization -Too many others to mention!
  • 87. "Hard to prove, easy to verify" Applied to a tokenizer “a,b,c” split “a” “b” “c” “a,b,c” Combine and verify To verify the tokenizer, just check that the concatenated tokens give us back the original string
  • 88. "Hard to prove, easy to verify" Applied to a sort To verify the sort, check that each pair is ordered [2;3;1] (1<=2) (2<=3) [1;2;3] List.sort
  • 89. ABC ABC 123 123 Compare System under test Test Oracle "The test oracle" - Compare optimized with slow brute-force version - Compare parallel with single thread version.
  • 90. PartV: Model based testing Using the test oracle approach for complex implementations
  • 91. Testing a simple database Open Incr Close Incr Open Close Open Decr Open Four operations: Open, Close, Increment, Decrement How do we know that our db works? Let QuickCheck generate a random list of these actions for each client Open Incr Client A Client B Two clients: Client A and Client B
  • 92. Testing a simple database Compare model result with real system! Open Incr Close Incr Open Close Open Decr Open Open Incr Test on real system Open Incr Close Incr Open Close Open Decr Open Open Incr Test on very simple model1 00 0 1 (just an in-memory accumulator)Connection closed, so no change
  • 93. Real world example • Subtle bugs in an Erlang module • The steps to reproduce were bizarre – open-close-open file then exactly 3 parallel ops – no human would ever think to write this test case • Shrinker critical in finding minimal sequence • War stories from John Hughes at https://vimeo.com/68383317
  • 95. Example-based tests vs. Property-based tests • PBTs are more general – One property-based test can replace many example- based tests. • PBTs can reveal overlooked edge cases – Nulls, negative numbers, weird strings, etc. • PBTs ensure deep understanding of requirements – Property-based tests force you to think!  • Example-based tests are still helpful though! – Easier to understand for newcomers
  • 96. Summary Be lazy! Don't write tests, generate them! Use property-based thinking to gain deeper insight into the requirements
  • 97. The lazy programmer's guide to writing 1000's of tests An introduction to property based testing Let us know if you need help with F# Thanks! @ScottWlaschin fsharpforfunandprofit.com/pbt fsharpworks.com Slides and video here Contact me