Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Property Based Testing

Property Based Testing

A short overview of property based testing using jsverify as the implementation.

Avatar for Hardy Jones

Hardy Jones

August 25, 2015

More Decks by Hardy Jones

Other Decks in Programming

Transcript

  1. Unit Test Result of a function Visible effects of a

    procedure Message sent from an object
  2. Integration Test Logging to a file Clicking a button and

    getting a POST request Ensuring two objects communicate
  3. But, what are the downsides? “...program testing can be a

    very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence.” - E.W. Disjkstra
  4. But, what are the downsides? “...program testing can be a

    very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence.” - E.W. Disjkstra Well, sort of...
  5. Associative Property 1 + (2 + 3) = (1 +

    2) + 3 (1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4
  6. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  7. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  8. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  9. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  10. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  11. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  12. var assert = require('assert'); describe('Addition for numbers', function() { describe('should

    not care about the order', function() { it('1 + (2 + 3) = (1 + 2) + 3', function() { assert(1 + (2 + 3) == (1 + 2) + 3); }); it('(1 + 2) + (3 + 4) = ((1 + 2) + 3) + 4', function() { assert((1 + 2) + (3 + 4) == ((1 + 2) + 3) + 4); }); }); …
  13. … describe('should have an identity', function() { it('1 + 0

    = 1', function() {assert(1 + 0 == 1);}); it('0 + 3 = 3', function() {assert(0 + 3 == 3);}); it('0 + 0 = 0', function() {assert(0 + 0 == 0);}); }); });
  14. … describe('should have an identity', function() { it('1 + 0

    = 1', function() {assert(1 + 0 == 1);}); it('0 + 3 = 3', function() {assert(0 + 3 == 3);}); it('0 + 0 = 0', function() {assert(0 + 0 == 0);}); }); });
  15. … describe('should have an identity', function() { it('1 + 0

    = 1', function() {assert(1 + 0 == 1);}); it('0 + 3 = 3', function() {assert(0 + 3 == 3);}); it('0 + 0 = 0', function() {assert(0 + 0 == 0);}); }); });
  16. … describe('should have an identity', function() { it('1 + 0

    = 1', function() {assert(1 + 0 == 1);}); it('0 + 3 = 3', function() {assert(0 + 3 == 3);}); it('0 + 0 = 0', function() {assert(0 + 0 == 0);}); }); });
  17. … describe('should have an identity', function() { it('1 + 0

    = 1', function() {assert(1 + 0 == 1);}); it('0 + 3 = 3', function() {assert(0 + 3 == 3);}); it('0 + 0 = 0', function() {assert(0 + 0 == 0);}); }); });
  18. … describe('should have an identity', function() { it('1 + 0

    = 1', function() {assert(1 + 0 == 1);}); it('0 + 3 = 3', function() {assert(0 + 3 == 3);}); it('0 + 0 = 0', function() {assert(0 + 0 == 0);}); }); });
  19. “...program testing can be a very effective way to show

    the presence of bugs, but is hopelessly inadequate for showing their absence.” - E.W. Disjkstra
  20. “...program testing can be a very effective way to show

    the presence of bugs, but is hopelessly inadequate for showing their absence.” - E.W. Disjkstra Proofs!
  21. QuickCheck Paper by Koen Claessen & John Hughes (2000) Haskell

    library circa 2006 node-quickcheck JSCheck
  22. QuickCheck Paper by Koen Claessen & John Hughes (2000) Haskell

    library circa 2006 node-quickcheck JSCheck Claire
  23. QuickCheck Paper by Koen Claessen & John Hughes (2000) Haskell

    library circa 2006 node-quickcheck JSCheck Claire JSVerify
  24. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  25. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  26. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  27. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  28. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  29. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  30. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  31. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  32. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  33. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  34. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  35. var jsverify = require('jsverify'); var assert = jsverify.assert; var forall

    = jsverify.forall; var nat = jsverify.nat; describe('Addition for numbers', function() { describe('should not care about the order', function() { var assoc = forall(nat, nat, nat, function(a, b, c) { return a + (b + c) == (a + b) + c; }); it('a + (b + c) = (a + b) + c', function() { assert(assoc); }); …
  36. … var identity = forall(nat, function(a) { return a +

    0 == a && 0 + a == a; }); it('a + 0 = a && 0 + a = a', function() { assert(identity); }); }); });
  37. … var identity = forall(nat, function(a) { return a +

    0 == a && 0 + a == a; }); it('a + 0 = a && 0 + a = a', function() { assert(identity); }); }); });
  38. … var identity = forall(nat, function(a) { return a +

    0 == a && 0 + a == a; }); it('a + 0 = a && 0 + a = a', function() { assert(identity); }); }); });
  39. … var identity = forall(nat, function(a) { return a +

    0 == a && 0 + a == a; }); it('a + 0 = a && 0 + a = a', function() { assert(identity); }); }); });
  40. … var identity = forall(nat, function(a) { return a +

    0 == a && 0 + a == a; }); it('a + 0 = a && 0 + a = a', function() { assert(identity); }); }); });
  41. Make our own arbitraries var elements = jsverify.elements; var lower

    = elements('abcdefghijklmnopqrstuvwxyz'.split('')); var upper = elements('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')); var digits = elements('0123456789'.split(''));
  42. Make our own arbitraries var elements = jsverify.elements; var lower

    = elements('abcdefghijklmnopqrstuvwxyz'.split('')); var upper = elements('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')); var digits = elements('0123456789'.split(''));
  43. Make our own arbitraries var elements = jsverify.elements; var lower

    = elements('abcdefghijklmnopqrstuvwxyz'.split('')); var upper = elements('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')); var digits = elements('0123456789'.split(''));
  44. Make our own arbitraries var elements = jsverify.elements; var lower

    = elements('abcdefghijklmnopqrstuvwxyz'.split('')); var upper = elements('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')); var digits = elements('0123456789'.split(''));
  45. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  46. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  47. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  48. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  49. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  50. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  51. Make our own arbitraries var tuple = jsverify.tuple; var proper

    = tuple([lower, upper, digits, lower, upper, digits, lower, upper ]).smap(function(chars) { return chars.join(''); }, function(str) { return str.split(''); });
  52. Make our own arbitraries var short = proper.smap(function(name) { return

    name.slice(-5); }, function(name) { return name; });
  53. Make our own arbitraries var short = proper.smap(function(name) { return

    name.slice(-5); }, function(name) { return name; });
  54. Make our own arbitraries var short = proper.smap(function(name) { return

    name.slice(-5); }, function(name) { return name; });
  55. Make our own arbitraries var short = proper.smap(function(name) { return

    name.slice(-5); }, function(name) { return name; });
  56. Make our own arbitraries var short = proper.smap(function(name) { return

    name.slice(-5); }, function(name) { return name; });
  57. describe('Validator', function() { describe('#username', function() { var properName = forall(proper,

    function(name) { return Validator.username(name); }); it('should validate a proper username', function() { assert(properName); }); …
  58. describe('Validator', function() { describe('#username', function() { var properName = forall(proper,

    function(name) { return Validator.username(name); }); it('should validate a proper username', function() { assert(properName); }); …
  59. describe('Validator', function() { describe('#username', function() { var properName = forall(proper,

    function(name) { return Validator.username(name); }); it('should validate a proper username', function() { assert(properName); }); …
  60. describe('Validator', function() { describe('#username', function() { var properName = forall(proper,

    function(name) { return Validator.username(name); }); it('should validate a proper username', function() { assert(properName); }); …
  61. … var badName = forall(short, function(name) { return !Validator.username(name); });

    it('should not validate a short username', function() { assert(badName); }); }); });
  62. … var badName = forall(short, function(name) { return !Validator.username(name); });

    it('should not validate a short username', function() { assert(badName); }); }); });
  63. … var badName = forall(short, function(name) { return !Validator.username(name); });

    it('should not validate a short username', function() { assert(badName); }); }); });
  64. … var badName = forall(short, function(name) { return !Validator.username(name); });

    it('should not validate a short username', function() { assert(badName); }); }); });
  65. Where do we go from here? Model with Property-based testing

    Strong static types (GHCjs, PureScript)
  66. Where do we go from here? Model with Property-based testing

    Strong static types (GHCjs, PureScript) Computer verified proofs (Idris)