SlideShare a Scribd company logo
How to Test
Asynchronous Code
     by Felix Geisendörfer




                             19.05.2011 (v2)
@felixge

Twitter / GitHub / IRC
Core Contributor

                                            &

                                  Module Author



             node-mysql                                  node-formidable


-   Joined the mailing list in June 26, 2009
-   When I joined there where #24 people
-   Now mailing list has close to 4000 members members
-   First patch in September 2009
- Disclaimer: Don’t listen to me : )
The current approach
test('something', function(done) {
  doSomethingAsync(function() {
    assert.equals(...);

    done();
  });
});
The current approach
test('something', function(done) {
  doSomethingAsync(function() {
    assert.equals(...);

    done();
  });
});
         If you have multiple tests, how will
                exceptions be linked?
db.query('SELECT A', function() {
      db.query('SELECT B', function() {
        db.query('SELECT C', function() {
          db.query('SELECT D', function() {
            // WTF
          });
        });
      });
    });




-   Who here is running node in production?
-   Raise hands if you have a test suite for your node.js projects
-   Raise hands if you are happy with it
-   But why is it so difficult?
test('something', function(done) {
     doSomethingAsync(function() {
       assert.equals(...);

       done();
     });
   });

                   F%$! that shit
Forget that shit
- We looked at asynchronous testing frameworks
- We really wanted to do TDD
- But everything we tried was hard
Take out the I/O
Stub / Mock Dependencies
Synchronous Tests
Unit Tests
If you have nested callbacks (or any other I/O) in your tests, you are not unit testing
Microtests
http://anarchycreek.com/2009/05/20/theyre-called-microtests/
•   It is short, typically under a dozen lines of code.
•   It is always automated.
•   It does not test the object inside the running app, but instead in a purpose-built testing application.
•   It invokes only a tiny portion of the code, most usually a single branch of a single function.
•   It is written gray-box, i.e. it reads as if it were black-box, but sometimes takes advantage of white-box knowledge. (Typically a critical factor in avoiding
    combinatoric issues.)
•   It is coded to the same standard as shipping code, i.e. the team’s best current understanding of coding excellence.
•   It is vault-committed source, with a lifetime co-terminous with the functionality it tests.
•   In combination with all other microtests of an app, it serves as a ‘gateway-to-commit’. That is, a developer is encouraged to commit anytime all microtests run
    green, and discouraged (strongly, even nastily) to commit otherwise.
•   It takes complete control of the object-under-test and is therefore self-contained, i.e. running with no dependencies on anything other than the testing code and
    its dependency graph.
•   It runs in an extremely short time, milliseconds per test.
•   It provides precise feedback on any errors that it encounters.
•   It usually (not always) runs entirely inside a single computer.
•   It usually (not always) runs entirely inside a single process, i.e. with few extra-process runtime dependencies.
•   It is part of a collection all or any subset of which is invokable with a single programmer gesture.
•   It is written before the code-change it is meant to test.
•   It avoids most or all usage of ‘awkward’ collaborators via a variety of slip-and-fake techniques.
•   It rarely involves construction of more than a few classes of object, often one or two, usually under five.
Approach
           • Load SUT in a Sandbox using v8 / node.js

           • Inject dependencies using the global object
               of the sandbox


           • Don’t use test doubles for internals, only
               for peers


Internal: An object that has the same life span as its host
Peers: Something that is being passed in / out of the SUT
Test Doubles
         • Dummy Object
         • Test Stub
         • Test Spy
         • Mock Object
         • Fake Object
         • Temporary Test Stub
http://xunitpatterns.com/Mocks,%20Fakes,%20Stubs%20and%20Dummies.html
How to Test Asynchronous Code (v2)
node-fake
var fake = require('fake')();
var object = {};

fake.expect(object, 'method');

object.method();
node-fake
var fake = require('fake')();
var object = {};

var objectMethodCall = fake.stub(object, 'method');

object.method();

assert.equals(objectMethodCall.calls.length, 1);
node-fake
var fake = require('fake')();

var MyClass = fake.class('MyClass');
fake
  .expect('new', MyClass)
  .withArgs(1, 2);

var myClass = new MyClass(1, 2);
How to Test Asynchronous Code (v2)
node-microtest

var fs = require('fs');

module.exports = function(path) {
   var file = fs.createReadStream(path);
   file.pipe(process.stdout);
};



                  cat.js
node-microtest

var test = require('microtest').module('cat.js');

test.requires('fs');
test.context.process = {
   stdout: test.object('stdout'),
};

var cat = test.compile();



                    test-cat.js
node-microtest
test.describe('cat', function() {
  var PATH = test.value('path');
  var file = test.object('file');

  test
    .expect(test.required.fs, 'createReadStream')
    .withArgs(PATH)
    .andReturn(file);

  test
    .expect(file, 'pipe')
    .withArgs(test.context.process.stdout);

  cat(PATH);
});

                   test-cat.js
Benefits
We take the position that the real benefit of extensive
microtest-driven development isn't higher quality at
all. Higher quality is a side effect of TDD. Rather, the
benefit and real purpose of TDD as we teach it is
sheer productivity: more function faster.

                                            Mike Hill
Benefits
• Simpler implementations

• Short change / verification cycles

• Tests for edge cases (error handling, race
  conditions, etc.)
There really are only two acceptable
models of development: "think and
analyze" or "years and years of
testing on thousands of machines".
                          Linus Torvalds
Disadvantages
          • Requires gray / white box knowledge of
              implementation


          • Lots of test code needs to be written

          • Sometimes feels awkward

http://martinfowler.com/articles/mocksArentStubs.html#ClassicalAndMockistTesting
How to Test Asynchronous Code (v2)
How to Test Asynchronous Code (v2)
node-mysql
                                        Lines of code

                         1.700

                         1.275

                           850

                           425

                             0
                                    library          tests

                      library vs test code: 1x : 1.35x
Library: 1240 LoC (+600 LoC MySql constants)Tests:
Tests: 1673 LoC
node-mysql
                                           Lines of code

                             1.300

                              975

                              650

                              325

                                0
                                     integration       micro

                  integration vs micro tests: 1x : 2.89x
Micro Tests: 1243 LoC
Integration tests: 430 LoC
node-mysql
                                             Assertions

                                400

                                300

                                200

                                100

                                  0
                                      integration         micro

                  integration vs micro tests: 1x : 8.15x
Micro Tests: 375 asserts
Integration tests: 46 asserts
How to Test Asynchronous Code (v2)
Transloadit
                                         Lines of code

                        13.000

                         9.750

                         6.500

                         3.250

                             0
                                     library         tests

                      library vs test code: 1x : 2.04x
Library: 6184 LoC
Tests: 12622 LoC

Not included: Fixture data, server configuration, customer website, dependencies we
developed
Transloadit
                                        Lines of code

                         10.000

                          7.500

                          5.000

                          2.500

                              0
                                  integration       micro

                 integration vs. micro tests: 1x : 4.30x
Integration tests: 2254 LoC
Micro Tests: 9695 LoC
Transloadit
                                            Assertions

                           3.000

                           2.250

                           1.500

                             750

                                 0
                                     integration         micro

                 integration vs. micro tests: 1x : 12.30x
Integration tests: 189 asserts
Micro Tests: 2324 asserts
tl;dr

• Don’t use integration tests to show the
  basic correctness of your software.


• Write more microtests.
Questions?
How to Test Asynchronous Code (v2)
Node.js Workshop Cologne



nodecologne.eventbrite.com

 Use discount code ‘berlinjs’ for 10% off

More Related Content

What's hot (20)

PDF
Nodejs - A quick tour (v6)
Felix Geisendörfer
 
KEY
Node.js - A practical introduction (v2)
Felix Geisendörfer
 
KEY
NodeJS
.toster
 
PDF
Nodejs - A quick tour (v5)
Felix Geisendörfer
 
KEY
Writing robust Node.js applications
Tom Croucher
 
PDF
Philly Tech Week Introduction to NodeJS
Ross Kukulinski
 
PPTX
introduction to node.js
orkaplan
 
PDF
Nodejs - A quick tour (v4)
Felix Geisendörfer
 
PDF
Dirty - How simple is your database?
Felix Geisendörfer
 
PPTX
Introduction Node.js
Erik van Appeldoorn
 
PDF
Original slides from Ryan Dahl's NodeJs intro talk
Aarti Parikh
 
PDF
Node.js - A Quick Tour
Felix Geisendörfer
 
PDF
Nodejs - A-quick-tour-v3
Felix Geisendörfer
 
PDF
Nodejs Explained with Examples
Gabriele Lana
 
PDF
NodeJS for Beginner
Apaichon Punopas
 
KEY
A million connections and beyond - Node.js at scale
Tom Croucher
 
PDF
NodeJS: an Introduction
Roberto Casadei
 
PDF
Building servers with Node.js
ConFoo
 
PDF
NodeJS
LinkMe Srl
 
PDF
Non-blocking I/O, Event loops and node.js
Marcus Frödin
 
Nodejs - A quick tour (v6)
Felix Geisendörfer
 
Node.js - A practical introduction (v2)
Felix Geisendörfer
 
NodeJS
.toster
 
Nodejs - A quick tour (v5)
Felix Geisendörfer
 
Writing robust Node.js applications
Tom Croucher
 
Philly Tech Week Introduction to NodeJS
Ross Kukulinski
 
introduction to node.js
orkaplan
 
Nodejs - A quick tour (v4)
Felix Geisendörfer
 
Dirty - How simple is your database?
Felix Geisendörfer
 
Introduction Node.js
Erik van Appeldoorn
 
Original slides from Ryan Dahl's NodeJs intro talk
Aarti Parikh
 
Node.js - A Quick Tour
Felix Geisendörfer
 
Nodejs - A-quick-tour-v3
Felix Geisendörfer
 
Nodejs Explained with Examples
Gabriele Lana
 
NodeJS for Beginner
Apaichon Punopas
 
A million connections and beyond - Node.js at scale
Tom Croucher
 
NodeJS: an Introduction
Roberto Casadei
 
Building servers with Node.js
ConFoo
 
NodeJS
LinkMe Srl
 
Non-blocking I/O, Event loops and node.js
Marcus Frödin
 

Similar to How to Test Asynchronous Code (v2) (20)

PPTX
Unit Testing
Sergey Podolsky
 
PPTX
NET Code Testing
Kirill Miroshnichenko
 
PPTX
Binary Studio Academy: .NET Code Testing
Binary Studio
 
PDF
Rethinking Testing
pdejuan
 
PDF
Building XWiki
Vincent Massol
 
PPTX
Loom promises: be there!
Jean-Francois James
 
PPTX
Resilience Testing
Ran Levy
 
PPTX
Clustrix Database Percona Ruby on Rails benchmark
Clustrix
 
PDF
CBDW2014 - MockBox, get ready to mock your socks off!
Ortus Solutions, Corp
 
KEY
Testing Zen
day
 
PDF
Inria Tech Talk : Comment améliorer la qualité de vos logiciels avec STAMP
Stéphanie Roger
 
PDF
FreeSWITCH as a Microservice
Evan McGee
 
KEY
Using Smalltalk for controlling robotics systems
Serge Stinckwich
 
PDF
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Nilesh Panchal
 
PDF
Microservices Application Tracing Standards and Simulators - Adrians at OSCON
Adrian Cockcroft
 
PDF
Gallio Crafting A Toolchain
ConSanFrancisco123
 
PDF
Performance Test Driven Development with Oracle Coherence
aragozin
 
PDF
D Trace Support In My Sql Guide To Solving Reallife Performance Problems
MySQLConference
 
PDF
Developers Testing - Girl Code at bloomon
Ineke Scheffers
 
PDF
Олександр Хотемський:”Serverless архітектура та її застосування в автоматизац...
Dakiry
 
Unit Testing
Sergey Podolsky
 
NET Code Testing
Kirill Miroshnichenko
 
Binary Studio Academy: .NET Code Testing
Binary Studio
 
Rethinking Testing
pdejuan
 
Building XWiki
Vincent Massol
 
Loom promises: be there!
Jean-Francois James
 
Resilience Testing
Ran Levy
 
Clustrix Database Percona Ruby on Rails benchmark
Clustrix
 
CBDW2014 - MockBox, get ready to mock your socks off!
Ortus Solutions, Corp
 
Testing Zen
day
 
Inria Tech Talk : Comment améliorer la qualité de vos logiciels avec STAMP
Stéphanie Roger
 
FreeSWITCH as a Microservice
Evan McGee
 
Using Smalltalk for controlling robotics systems
Serge Stinckwich
 
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Nilesh Panchal
 
Microservices Application Tracing Standards and Simulators - Adrians at OSCON
Adrian Cockcroft
 
Gallio Crafting A Toolchain
ConSanFrancisco123
 
Performance Test Driven Development with Oracle Coherence
aragozin
 
D Trace Support In My Sql Guide To Solving Reallife Performance Problems
MySQLConference
 
Developers Testing - Girl Code at bloomon
Ineke Scheffers
 
Олександр Хотемський:”Serverless архітектура та її застосування в автоматизац...
Dakiry
 
Ad

Recently uploaded (20)

PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
Python basic programing language for automation
DanialHabibi2
 
PDF
July Patch Tuesday
Ivanti
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PPTX
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Timothy Rottach - Ramp up on AI Use Cases, from Vector Search to AI Agents wi...
AWS Chicago
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
Python basic programing language for automation
DanialHabibi2
 
July Patch Tuesday
Ivanti
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Timothy Rottach - Ramp up on AI Use Cases, from Vector Search to AI Agents wi...
AWS Chicago
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
Ad

How to Test Asynchronous Code (v2)

  • 1. How to Test Asynchronous Code by Felix Geisendörfer 19.05.2011 (v2)
  • 3. Core Contributor & Module Author node-mysql node-formidable - Joined the mailing list in June 26, 2009 - When I joined there where #24 people - Now mailing list has close to 4000 members members - First patch in September 2009
  • 4. - Disclaimer: Don’t listen to me : )
  • 5. The current approach test('something', function(done) { doSomethingAsync(function() { assert.equals(...); done(); }); });
  • 6. The current approach test('something', function(done) { doSomethingAsync(function() { assert.equals(...); done(); }); }); If you have multiple tests, how will exceptions be linked?
  • 7. db.query('SELECT A', function() { db.query('SELECT B', function() { db.query('SELECT C', function() { db.query('SELECT D', function() { // WTF }); }); }); }); - Who here is running node in production? - Raise hands if you have a test suite for your node.js projects - Raise hands if you are happy with it - But why is it so difficult?
  • 8. test('something', function(done) { doSomethingAsync(function() { assert.equals(...); done(); }); }); F%$! that shit Forget that shit
  • 9. - We looked at asynchronous testing frameworks - We really wanted to do TDD - But everything we tried was hard
  • 11. Stub / Mock Dependencies
  • 13. Unit Tests If you have nested callbacks (or any other I/O) in your tests, you are not unit testing
  • 14. Microtests http://anarchycreek.com/2009/05/20/theyre-called-microtests/ • It is short, typically under a dozen lines of code. • It is always automated. • It does not test the object inside the running app, but instead in a purpose-built testing application. • It invokes only a tiny portion of the code, most usually a single branch of a single function. • It is written gray-box, i.e. it reads as if it were black-box, but sometimes takes advantage of white-box knowledge. (Typically a critical factor in avoiding combinatoric issues.) • It is coded to the same standard as shipping code, i.e. the team’s best current understanding of coding excellence. • It is vault-committed source, with a lifetime co-terminous with the functionality it tests. • In combination with all other microtests of an app, it serves as a ‘gateway-to-commit’. That is, a developer is encouraged to commit anytime all microtests run green, and discouraged (strongly, even nastily) to commit otherwise. • It takes complete control of the object-under-test and is therefore self-contained, i.e. running with no dependencies on anything other than the testing code and its dependency graph. • It runs in an extremely short time, milliseconds per test. • It provides precise feedback on any errors that it encounters. • It usually (not always) runs entirely inside a single computer. • It usually (not always) runs entirely inside a single process, i.e. with few extra-process runtime dependencies. • It is part of a collection all or any subset of which is invokable with a single programmer gesture. • It is written before the code-change it is meant to test. • It avoids most or all usage of ‘awkward’ collaborators via a variety of slip-and-fake techniques. • It rarely involves construction of more than a few classes of object, often one or two, usually under five.
  • 15. Approach • Load SUT in a Sandbox using v8 / node.js • Inject dependencies using the global object of the sandbox • Don’t use test doubles for internals, only for peers Internal: An object that has the same life span as its host Peers: Something that is being passed in / out of the SUT
  • 16. Test Doubles • Dummy Object • Test Stub • Test Spy • Mock Object • Fake Object • Temporary Test Stub http://xunitpatterns.com/Mocks,%20Fakes,%20Stubs%20and%20Dummies.html
  • 18. node-fake var fake = require('fake')(); var object = {}; fake.expect(object, 'method'); object.method();
  • 19. node-fake var fake = require('fake')(); var object = {}; var objectMethodCall = fake.stub(object, 'method'); object.method(); assert.equals(objectMethodCall.calls.length, 1);
  • 20. node-fake var fake = require('fake')(); var MyClass = fake.class('MyClass'); fake .expect('new', MyClass) .withArgs(1, 2); var myClass = new MyClass(1, 2);
  • 22. node-microtest var fs = require('fs'); module.exports = function(path) { var file = fs.createReadStream(path); file.pipe(process.stdout); }; cat.js
  • 23. node-microtest var test = require('microtest').module('cat.js'); test.requires('fs'); test.context.process = { stdout: test.object('stdout'), }; var cat = test.compile(); test-cat.js
  • 24. node-microtest test.describe('cat', function() { var PATH = test.value('path'); var file = test.object('file'); test .expect(test.required.fs, 'createReadStream') .withArgs(PATH) .andReturn(file); test .expect(file, 'pipe') .withArgs(test.context.process.stdout); cat(PATH); }); test-cat.js
  • 25. Benefits We take the position that the real benefit of extensive microtest-driven development isn't higher quality at all. Higher quality is a side effect of TDD. Rather, the benefit and real purpose of TDD as we teach it is sheer productivity: more function faster. Mike Hill
  • 26. Benefits • Simpler implementations • Short change / verification cycles • Tests for edge cases (error handling, race conditions, etc.)
  • 27. There really are only two acceptable models of development: "think and analyze" or "years and years of testing on thousands of machines". Linus Torvalds
  • 28. Disadvantages • Requires gray / white box knowledge of implementation • Lots of test code needs to be written • Sometimes feels awkward http://martinfowler.com/articles/mocksArentStubs.html#ClassicalAndMockistTesting
  • 31. node-mysql Lines of code 1.700 1.275 850 425 0 library tests library vs test code: 1x : 1.35x Library: 1240 LoC (+600 LoC MySql constants)Tests: Tests: 1673 LoC
  • 32. node-mysql Lines of code 1.300 975 650 325 0 integration micro integration vs micro tests: 1x : 2.89x Micro Tests: 1243 LoC Integration tests: 430 LoC
  • 33. node-mysql Assertions 400 300 200 100 0 integration micro integration vs micro tests: 1x : 8.15x Micro Tests: 375 asserts Integration tests: 46 asserts
  • 35. Transloadit Lines of code 13.000 9.750 6.500 3.250 0 library tests library vs test code: 1x : 2.04x Library: 6184 LoC Tests: 12622 LoC Not included: Fixture data, server configuration, customer website, dependencies we developed
  • 36. Transloadit Lines of code 10.000 7.500 5.000 2.500 0 integration micro integration vs. micro tests: 1x : 4.30x Integration tests: 2254 LoC Micro Tests: 9695 LoC
  • 37. Transloadit Assertions 3.000 2.250 1.500 750 0 integration micro integration vs. micro tests: 1x : 12.30x Integration tests: 189 asserts Micro Tests: 2324 asserts
  • 38. tl;dr • Don’t use integration tests to show the basic correctness of your software. • Write more microtests.
  • 41. Node.js Workshop Cologne nodecologne.eventbrite.com Use discount code ‘berlinjs’ for 10% off