Namir Sayed-Ahmad Baraza
a device that has a specified function, especially one forming part of a complex mechanism
a piece of code that has a specified function, especially one forming part of a complex program
Unit
Module
System
A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work.
Our company, Calculator GmbH, needs a brand new feature. A function that allows them to sum 2 numbers!
sum = function sum(a, b) {
return a + b;
}
We are incredible programmers, so we go to our C9 editor, and we write this:
The "beloved" project leader reviews the code and say:
git checkout presentation-unit-testing-sum-step-1
He shows you how to write the tests. He encourages you to write them before your actual code:
describe('sum', function() {
it('should sum two numbers and give the result', function () {
// Given two numbers
const a = 2;
const b = 4;
// When i call sum with them as arguments
const result = sum(a, b);
// Then the result should be the sum of both
expect(result).toBe(6);
});
it('should throw an error if any of the arguments is not a number', function () {
// Given two input, one number and another one which is not a number
const a = 2;
const b = '4';
// When I call sum with them as arguments
// Then the function should throw an error
expect(() => { sum(a, b); }).toThrow();
});
it('should consider only the value of the inputs not the sign', function () {
// Given two inputs, one positive number and one negative number
const a = 2;
const b = -4;
// When I call sum with them as arguments
const result = sum(a, b);
// Then the result should be the soum of both values ignoring the sign
expect(result).toBe(6);
});
});
git checkout presentation-unit-testing-sum-step-2
Now, you run them and...
jasmine-server-integration: 2 tests failed
CONSOLE (STDERR) sum should throw an error if any of the arguments is not a number
CONSOLE (STDERR) Expected function to throw an exception.
CONSOLE (STDERR) meteor://💻app/tests/unit/sum.spec.js:18:38: Expected function to throw an exception.
CONSOLE (STDERR)
CONSOLE (STDERR) sum should consider only the value of the inputs not the sign
CONSOLE (STDERR) Expected -2 to be 6.
CONSOLE (STDERR) meteor://💻app/tests/unit/sum.spec.js:28:24: Expected -2 to be 6.
./testPackages.sh packages/sum/
sum = function sum (a, b) {
// Check not numbers
const typeOfA = typeof a;
const typeOfB = typeof b;
// We check the type of the arguments
if (typeOfA !== 'number' || typeOfB !== 'number') {
throw new TypeError('Arguments must be numbers');
}
return Math.abs(a) + Math.abs(b); // We ignore the sign
};
git checkout presentation-unit-testing-sum-step-3
./testPackages.sh packages/sum/
We run our tests again
jasmine-server-integration: 3 tests passed (10ms)
We've written our first succesful tests!
Project Leader
We must only allow integers!
You
git checkout presentation-unit-testing-sum-step-4
sum = function sum (a, b) {
// We check the type of the arguments
if (!Number.isInteger(a) || !Number.isInteger(b)) {
throw new TypeError('Arguments must be numbers');
}
return Math.abs(a) + Math.abs(b); // We ignore the sign
};
./testPackages.sh packages/sum/
We run our tests again
jasmine-server-integration: 4 tests passed (10ms)
All our tests still pass!
it(`should throw an error if any of the arguments
is not a integer`, function () {
// Given two arguments,
const a = 2; // A integer
const b = 4.2; // And a float
// When i call sum with them as arguments
// Then the result should be the sum of both
expect(() => { sum(a, b); }).toThrow();
});
Project Leader
We must log every operation to the Database!
You
A good unit test is
Able to be fully automated
Has full control over all the pieces running
Can be run in any order if part of many other tests
Runs in memory (no DB, Network or File access)
Project Leader
We must log every operation to the Database!
Doubles to the rescue!
We have some types of test doubles:
// spyOn OperationLog
// We spy because we want to check if the database was called
beforeEach(function () {
spyOn(OperationLog, 'insert'); // OperationLog is the Collection
});
// Add one test
it('should log every operation to the database', function () {
// Given two numbers
const a = 2;
const b = 4;
// When i call sum with them as arguments
const result = sum(a, b);
// Then the OperationLog should be updated
expect(OperationLog.insert).toHaveBeenCalledWith({
operation: 'sum',
args: [a, b],
result
});
});
git checkout presentation-unit-testing-sum-step-5
sum = function sum (a, b) {
// We check the type of the arguments
if (!Number.isInteger(a) || !Number.isInteger(b)) {
throw new TypeError('Arguments must be numbers');
}
const result = Math.abs(a) + Math.abs(b); // We ignore the sign
OperationLog.insert({
operation: 'sum',
args: [a, b],
result
});
return result;
};
./testPackages.sh packages/sum/
We run our tests again
jasmine-server-integration: 5 tests passed (10ms)
All our tests pass!
But....
Testing helps you to write specifications/requirements before starting to code
Testing helps you to make changes in the code without being scared about breaking it
Testing allows you to develop features faster, because you don't need to manually test everystep on every reload.
Testing can help you to write better code
Questions time!