7. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 7
"Program testing can be a very
effective way to show the presence of
bugs, but it is hopelessly inadequate
for showing their absence."
- Edsger Dijkstra
21. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 21
it('keeps the same length', () => {
const arr = arrayOfRandomNumbers();
expect(sort(arr).length).toEqual(arr.length);
});
it('is idempotent', () => {
const arr = arrayOfRandomNumbers();
expect(sort(sort(arr))).toEqual(sort(arr));
});
it('every member is less than or equal to the next one', () => {
const arr = arrayOfRandomNumbers();
const sorted = sort(arr);
for (let i in sorted) {
const current = sorted[i];
const next = sorted[i + 1];
if (next !== undefined) {
expect(current).toBeLessThanOrEqual(next);
}
}
});
22. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 22
it('keeps the same length', () => {
const arr = arrayOfRandomNumbers();
expect(sort(arr).length).toEqual(arr.length);
});
it('is idempotent', () => {
const arr = arrayOfRandomNumbers();
expect(sort(sort(arr))).toEqual(sort(arr));
});
it('every member is less than or equal to the next one', () => {
const arr = arrayOfRandomNumbers();
const sorted = sort(arr);
for (let i in sorted) {
const current = sorted[i];
const next = sorted[i + 1];
if (next !== undefined) {
expect(current).toBeLessThanOrEqual(next);
}
}
});
23. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 23
it('keeps the same length', () => {
const arr = arrayOfRandomNumbers();
expect(sort(arr).length).toEqual(arr.length);
});
it('is idempotent', () => {
const arr = arrayOfRandomNumbers();
expect(sort(sort(arr))).toEqual(sort(arr));
});
it('every member is less than or equal to the next one', () => {
const arr = arrayOfRandomNumbers();
const sorted = sort(arr);
for (let i in sorted) {
const current = sorted[i];
const next = sorted[i + 1];
if (next !== undefined) {
expect(current).toBeLessThanOrEqual(next);
}
}
});
25. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 25
"Example-Based tests are very narrow
in their input and broad in their
expectations."
- Jessica Kerr
42. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 42
import { gen } from 'testcheck';
check.it('is idempotent', gen.array(gen.int), arr => {
expect(sort(sort(arr))).toEqual(sort(arr));
});
43. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 43
import { gen } from 'testcheck';
check.it('is idempotent', gen.array(gen.int), arr => {
expect(sort(sort(arr))).toEqual(sort(arr));
});
44. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 44
import { gen } from 'testcheck';
check.it('keeps the same length', gen.array(gen.int), arr => {
expect(sort(arr).length).toEqual(arr.length);
});
check.it('is idempotent', gen.array(gen.int), arr => {
expect(sort(sort(arr))).toEqual(sort(arr));
});
check.it('every member is less than or equal to the next one',
gen.array(gen.int), arr => {
const sorted = sort(arr);
for (let i in sorted) {
const current = sorted[i];
const next = sorted[i + 1];
if (next !== undefined) {
expect(current).toBeLessThanOrEqual(next);
}
}
});
49. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 49
Where does it fall
apart in JavaScript?
50. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 50
type Person = {
name: string,
age: number,
};
function savePerson(person: Person): Person
import { gen } from 'testcheck';
const personGen = gen.object({
name: gen.alphaNumString,
age: gen.posInt,
});
51. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 51
type Person = {
name: string,
age: number,
};
function savePerson(person: Person): Person
import { gen } from 'testcheck';
const personGen = gen.object({
name: gen.alphaNumString,
age: gen.posInt,
});
52. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 52
type Person = {
name: string,
age: number,
};
function savePerson(person: Person): Person
import { gen } from 'testcheck';
const personGen = gen.object({
name: gen.alphaNumString,
age: gen.posInt,
});
60. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 60
import type {ActivationRule as ActivationRuleV0} from './v00';
import type {ActivationRule as ActivationRuleV1} from './v01';
import type {ActivationRule as ActivationRuleV2} from './v02';
import type {ActivationRule as ActivationRuleV3} from './v03';
import type {ActivationRule as ActivationRuleV4} from './v04';
import type {ActivationRule as ActivationRuleV5} from './v05';
import type {ActivationRule as ActivationRuleV6} from './v06';
import type {ActivationRule as ActivationRuleV7} from './v07';
import type {ActivationRule as ActivationRuleV8} from './v08';
import type {ActivationRule as ActivationRuleV9} from './v09';
import type {ActivationRule as ActivationRuleV10} from './v10';
type AnyActivationRule =
ActivationRuleV10 |
ActivationRuleV9 |
ActivationRuleV8 |
ActivationRuleV7 |
ActivationRuleV6 |
ActivationRuleV5 |
ActivationRuleV4 |
ActivationRuleV3 |
ActivationRuleV2 |
ActivationRuleV1 |
ActivationRuleV0;
61. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce
const upgradeActivationRule =
(version: number, rule: AnyActivationRule): AnyActivationRule
61
84. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 84
TS and Flow can now
force declarations to sync
☹😀
85. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce 85
Property-Based Testing
finds flaws in your code.
Lets make it easy to do in
JavaScript.
88. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce
import uuid from 'uuid/v4';
import type { $Gen } from 'babel-plugin-transform-flow-to-gen/Gen';
// type $Gen<T, _U> = T;
type User = {
id: $Gen<string, uuid>;
name: string;
}
89. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce
// use higher order type in JS
const janitorGen = Worker.toGen(gen.object({type: 'janitor'}));
// OR create type in Flow
type Janitor = Worker<{type: 'janitor'}>;
const janitorGen = Janitor.toGen();
90. Property-Based Testing for Godly Tests - Gabe Scholz @unbounce
import { generator } from 'my-lib';
import { AnyActivationRule } from './types';
const activationRuleGen =
generator<AnyActivationRule>();
// function generator<T>(): T;