• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Functional programming's relentless bug hunter  claire

Functional programming's relentless bug hunter claire






Total Views
Views on SlideShare
Embed Views



0 Embeds 0

No embeds



Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

    Functional programming's relentless bug hunter  claire Functional programming's relentless bug hunter claire Presentation Transcript

    • FunctionalProgrammingsRelentless Bug Hunter:ClaireAdam Bakeradam@dobetter.com
    • Property Based TestingYou may have heard of this from libraries such asQuickCheck and ScalaCheckClaire is a library by Quildreen Motta that helps you testinvariants in your javascript
    • Invariants!We are used to writing tests like this:eπi = -1We should start writing tests like this:∀x. exi = cos(x) + i sin(x)
    • Invariants!An old idea in computer sciencePreconditions and PostconditionsLoop InvariantsUsually expressed in a functional language
    • The Strategy1. Define generators2. Identify invariants3. Convert to Claire property4. Test property on generated data5. ...6. No more bugs!
    • Generators, Properties,Testsvar claire = require(claire)var _ = claire.data//two generators, Int and Numvar commutativity = claire.forAll(_.Int, _.Num).satisfy(function(integer, real){ //the property being testedreturn integer+real === real+integer}).asTest() //returns a function//use it in mochadescribe(addition, function(){it(is commutative, commutativity)})//or invoke it to see the resultscommutativity() //passes silently
    • Diagnosing Propertiesvar sorted_p = forAll( _.Array(_.Int) ).satisfy(function(xs) {xs = sorted(xs)return xs.every(function(a, i) {return i == 0 || a >= xs[i - 1]})}).classify(function(xs) {return xs.length == 0 || xs.length == 1? trivial : > 1}).asTest({verbose: true, times: 1000})()// + OK passed 1000 tests.// > Collected test data:// o 98% - > 1// o 2% - trivial
    • A Simple ExampleFrom a real appTo the command line!
    • Generators from a morecomplex examplefunction modelObjGen(className, attrGens) {return claire.label(className)(function() {var attr, attrs, gen;attrs = {};for (attr in attrGens) {gen = attrGens[attr];attrs[attr] = gen.next().value;}return new App.Models[className](attrs);});};
    • Generators from a morecomplex examplevar SpecialItem = classObjGen(SpecialItem, {type: claire.choice(Feedback, ContactForm, Document),info: gens.resize(5, ObjectGen(Any))});var Video = classObjGen(Video, {youTubeId: claire.frequency([1, Nothing], [9, Id])});var Item = claire.label(Item, claire.choice(SpecialItem, Video));var Unit = classObjGen(Unit, {items: gens.resize(6, ArrayGen(Item))});
    • Properties of Addition andMultiplicationassociativity: (a+b)+c = a+(b+c)commutativity: a+b = b+aidentity: a+0 = aclosure: ∀ a,b ∈ ℤ. (a+b) ∈ ℤTest with Int, Num, and BigIntfor both addition and multiplicationWhich ones fail?
    • Properties of Addition andMultiplicationTwo failures:Num fails associativity of multiplicationBigInt fails associativity of additionThe Point: Claire makes it easy to test boundary conditionsand find corner cases.
    • A Look InsideSome basic generators:char = String.from-char-code### -- Primitive data types --------------------------------------------Null = as-generator nullUndefined = as-generator voidBool = choice true, falseNum = label num ((s) -> choose -s, s)Byte = label byte ((_) -> to-integer (choose 0, 255))Char = label char (transform char, Byte)Str = label str (transform join, (repeat Char))
    • Container Type Generators### -- Container data types -------------------------------List = (...as) -> repeat (choice ...as)Map = (...as) -> transform to-object, (repeat (sequence Id, (choice ...as)))#### λ to-object# :internal:# Folds a list of pairs into an object.## :: [String, a] -> { String -> a }to-object = (as) -> as.reduce ((r, [k,v]) -> r <<< { "#k": v }), {}
    • For the FP geeksClaires generators are monads:claire.transformacts as fmap.thenmethod on generators acts as monadic bind
    • Whats in the Future?1. Shrinking of counterexamples.2. Generators based on generic lazy linked lists3. Asynchronous tests
    • Why is this important?Automated teting is important.XUnit testing automates test running.Propery based testing automates test generation.Shrinking will help automate the first step in debugging.Your confidence grows each time you run your test suite.Random data (often) finds corners better than I do.
    • Thanksinstall:npm install clairegithub:a talk on QuickCheck by John Hughes.https://github.com/killdream/claireFunctional Programming: A Secret Weapon for SoftwareTesting