SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
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
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
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
17.
node-fake
var fake = require('fake')();
var object = {};
fake.expect(object, 'method');
object.method();
18.
node-fake
var fake = require('fake')();
var object = {};
var objectMethodCall = fake.stub(object, 'method');
object.method();
assert.equals(objectMethodCall.calls.length, 1);
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.
node-microtest
var fs = require('fs');
module.exports = function(path) {
var file = fs.createReadStream(path);
file.pipe(process.stdout);
};
cat.js
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.
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.
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
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.
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.
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.
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
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.
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