Skip to content

Instantly share code, notes, and snippets.

@graue
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graue/b86d52335a328f916d1f to your computer and use it in GitHub Desktop.
Save graue/b86d52335a328f916d1f to your computer and use it in GitHub Desktop.
Styles of property-based testing in JavaScript
// Option #1
prop('addition is commutative', [Number, Number], function(a, b) {
return add(a, b) === add(b, a);
});
// Option #2
prop('addition is commutative', function(any) {
var a = any(Number);
var b = any(Number);
return add(a, b) === add(b, a);
});
// Option #3
prop('addition is commutative', function() {
var a = gentest.gen(Number);
var b = gentest.gen(Number);
return add(a, b) === add(b, a);
});
// Option #4
prop('addition is commutative', function() {
var a = this.get(Number);
var b = this.get(Number);
return add(a, b) === add(b, a);
});
// Option #5
prop('addition is commutative',
[gentest.types.int, gentest.types.int],
function(a, b) {
return add(a, b) === add(b, a);
});
// Option #6
prop('addition is commutative', function(a, b) {
return add(a, b) === add(b, a);
}, [gentest.types.int, gentest.types.int]);
// Option #7
var tests = [
{
name: 'addition is commutative',
prop: function(a, b) {
return add(a, b) === add(b, a);
},
argTypes: [gentest.types.int, gentest.types.int]
}
];
// Option #8
var prop_isCommutative = function(a, b) {
return add(a, b) === add(b, a);
};
gentest.run(prop_isCommutative,
gentest.types.int,
gentest.types.int);
// Option #9a
forAll({a: Number, b: Number}, function() {
return add(this.a, this.b) === add(this.b, this.a);
});
// Option #9b
forAll({a: Number, b: Number}, function(r) {
return add(r.a, r.b) === add(r.b, r.a);
});
// Option #10
describe('addition', function() {
it('is commutative',
{a: Number, b: Number},
function(r) {
return add(r.a, r.b) === add(r.b, r.a);
}
);
it('is associative',
{a: Number, b: Number, c: Number},
function(r) {
return add(r.a, add(r.b, r.c)) === add(add(r.a, r.b), r.c);
}
);
});
@graue
Copy link
Author

graue commented Aug 6, 2014

Leaning towards a modification of #9b without abusing built-in constructors (instead of Number, we'll stick to gentest.types.int), and presenting two choices:

var t = gentest.types;

// usage: forAll(obj || array, name, func)

// pass an object, get a context with generated values as attributes
forAll({a: t.int, b: t.int}, 'addition is commutative', function(ctx) {
  var a = ctx.a, b = ctx.b;
  return add(a, b) === add(b, a);
});

// or...
// pass an array, get generated values as arguments
forAll([t.int, t.int], 'addition is commutative', function(a, b) {
  return add(a, b) === add(b, a);
});

Completely a matter of preference. The manual handling of ctx in the first example is crummy boilerplate to have to write, but it's not the end of the world, and the first style will become awesome when using either esnext (once destructuring is added):

forAll({a: t.int, b: t.int}, 'addition is commutative', function({a, b}) {
  return add(a, b) === add(b, a);
});

or CoffeeScript:

forAll {a: t.int, b: t.int}, 'addition is commutative', ({a, b}) ->
  add(a, b) == add(b, a)

So with good sugar on the way, and available already for those willing to use CoffeeScript, I think it's too good to resist offering that option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment