Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

How to Test Asynchronous Code (v2)

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
How to Test
Asynchronous Code
     by Felix Geisendörfer




                             19.05.2011 (v2)
@felixge

Twitter / GitHub / IRC
Core Contributor

                                            &

                                  Module Author



      ...
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Wird geladen in …3
×

Hier ansehen

1 von 41 Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Ähnlich wie How to Test Asynchronous Code (v2) (20)

Anzeige

Aktuellste (20)

How to Test Asynchronous Code (v2)

  1. 1. How to Test Asynchronous Code by Felix Geisendörfer 19.05.2011 (v2)
  2. 2. @felixge Twitter / GitHub / IRC
  3. 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. 4. - Disclaimer: Don’t listen to me : )
  5. 5. The current approach test('something', function(done) { doSomethingAsync(function() { assert.equals(...); done(); }); });
  6. 6. The current approach test('something', function(done) { doSomethingAsync(function() { assert.equals(...); done(); }); }); If you have multiple tests, how will exceptions be linked?
  7. 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. 8. test('something', function(done) { doSomethingAsync(function() { assert.equals(...); done(); }); }); F%$! that shit Forget that shit
  9. 9. - We looked at asynchronous testing frameworks - We really wanted to do TDD - But everything we tried was hard
  10. 10. Take out the I/O
  11. 11. Stub / Mock Dependencies
  12. 12. Synchronous Tests
  13. 13. Unit Tests If you have nested callbacks (or any other I/O) in your tests, you are not unit testing
  14. 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. 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. 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
  17. 17. node-fake var fake = require('fake')(); var object = {}; fake.expect(object, 'method'); object.method();
  18. 18. node-fake var fake = require('fake')(); var object = {}; var objectMethodCall = fake.stub(object, 'method'); object.method(); assert.equals(objectMethodCall.calls.length, 1);
  19. 19. node-fake var fake = require('fake')(); var MyClass = fake.class('MyClass'); fake .expect('new', MyClass) .withArgs(1, 2); var myClass = new MyClass(1, 2);
  20. 20. node-microtest var fs = require('fs'); module.exports = function(path) { var file = fs.createReadStream(path); file.pipe(process.stdout); }; cat.js
  21. 21. 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
  22. 22. 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
  23. 23. 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
  24. 24. Benefits • Simpler implementations • Short change / verification cycles • Tests for edge cases (error handling, race conditions, etc.)
  25. 25. There really are only two acceptable models of development: "think and analyze" or "years and years of testing on thousands of machines". Linus Torvalds
  26. 26. 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
  27. 27. 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
  28. 28. 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
  29. 29. 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
  30. 30. 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
  31. 31. 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
  32. 32. 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
  33. 33. tl;dr • Don’t use integration tests to show the basic correctness of your software. • Write more microtests.
  34. 34. Questions?
  35. 35. Node.js Workshop Cologne nodecologne.eventbrite.com Use discount code ‘berlinjs’ for 10% off

×