Understand what Jasmine and unit testing are
Define describe, it, matchers, and spies
Write better tests with before and after hooks
Write asynchronous tests with clocks and done callbacks
Compare and contrast TDD and BDD and differentiate between unit and other kinds of tests
Write unit tests using Jasmine!
But some of them are preventable...
Specifically unit tests!
Unit tests, test parts of an application, (or units). Very commonly, each unit is tested individually and independently to ensure an application is running as expected
A framework to write tests
A way of describing the code we are testing
A tool where we can make assertions or expectations about our code
We will be working in the browser!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jasmine Tests</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/jasmine.css">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/jasmine.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/jasmine-html.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/boot.js"></script>
</body>
</html>
Check it out! http://bit.ly/2s0GA3C
describe
- "let me tell you about _____"
expect
- "let me describe ____ to you."
it
- "here's what I expect"
describe("Earth")
it("is round")
expect(earth.isRound.toBe(true))
it("is the third planet from the sun")
expect(earth.numberFromSun).toBe(3)
var earth = {
isRound: true,
numberFromSun: 3
}
describe("Earth", function(){
it("is round", function(){
expect(earth.isRound).toBe(true)
});
it("is the third planet from the sun", function(){
expect(earth.numberFromSun).toBe(3)
});
});
describe, it, and expect are given to us by Jasmine!
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/jasmine.css">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/jasmine.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/jasmine-html.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.6.2/boot.js"></script>
<script>
var earth = {
isRound: true,
numberFromSun: 3
}
describe("Earth", function(){
it("is round", function(){
expect(earth.isRound).toBe(true)
});
it("is the third planet from the sun", function(){
expect(earth.numberFromSun).toBe(3)
});
});
</script>
</body>
</html>
Check it out! http://bit.ly/2qC8CmG
toBe / not.toBe
toBeCloseTo
toBeDefined
toBeFalsey / toBeTruthy
toBeGreaterThan / toBeLessThan
toContain
toEqual
jasmine.any()
describe("Jasmine Matchers", function() {
});
Check it out! http://bit.ly/2sfBOgx
it("allows for === and deep equality", function() {
expect(1+1).toBe(2);
expect([1,2,3]).toEqual([1,2,3]);
});
it("allows for easy precision checking", function() {
expect(3.1415).toBeCloseTo(3.14,2);
});
it("allows for easy truthy / falsey checking", function() {
expect(0).toBeFalsy();
expect([]).toBeTruthy();
});
it("allows for checking contents of an object", function() {
expect([1,2,3]).toContain(1);
expect({name:'Elie'}).toEqual(jasmine.objectContaining({name:'Elie'}));
});
it("allows for easy type checking", function() {
expect([]).toEqual(jasmine.any(Array));
expect(function(){}).toEqual(jasmine.any(Function));
});
describe("#push", function(){
it("adds elements to an array", function(){
var arr = [1,3,5];
arr.push(7);
expect(arr).toEqual([1,3,5,7]);
});
it("returns the new length of the array", function(){
var arr = [1,3,5];
expect(arr.push(7)).toBe(4);
});
it("adds anything into the array", function(){
var arr = [1,3,5];
expect(arr.push({})).toBe(4);
});
});
defining the arr variable over and over!
describe("Arrays", function(){
var arr;
beforeEach(function(){
arr = [1,3,5];
});
});
run before each "it" callback
describe("Arrays", function(){
var arr;
beforeEach(function(){
arr = [1,3,5];
});
it("adds elements to an array", function(){
arr.push(7);
expect(arr).toEqual([1,3,5,7]);
});
it("returns the new length of the array", function(){
expect(arr.push(7)).toBe(4);
});
it("adds anything into the array", function(){
expect(arr.push({})).toBe(4);
});
});
run after each "it" callback - useful for teardown
describe("Counting", function(){
var count = 0;
beforeEach(function(){
count++;
});
afterEach(function(){
count = 0;
});
it("has a counter that increments", function(){
expect(count).toBe(1);
});
it("gets reset", function(){
expect(count).toBe(1);
});
});
run before/after all tests! Does not reset in between
var arr = [];
beforeAll(function(){
arr = [1,2,3];
})
describe("Counting", function(){
it("starts with an array", function(){
arr.push(4);
expect(1).toBe(1);
});
it("keeps mutating that array", function(){
console.log(arr); // [1,2,3,4]
arr.push(5);
expect(1).toBe(1);
});
});
describe("Again", function(){
it("keeps mutating the array...again", function(){
console.log(arr); // [1,2,3,4,5]
expect(1).toBe(1);
});
});
describe("Array", function(){
var arr;
beforeEach(function(){
arr = [1,3,5];
});
});
describe("#unshift", function(){
it("adds an element to the beginning of an array", function(){
arr.unshift(17);
expect(arr[0]).toBe(17);
});
it("returns the new length", function(){
expect(arr.unshift(1000)).toBe(4);
});
});
describe("#push", function(){
it("adds elements to the end of an array", function(){
arr.push(7);
expect(arr[arr.length-1]).toBe(7);
});
it("returns the new length", function(){
expect(arr.push(1000)).toBe(4);
});
});
describe("Pending specs", function(){
});
Sometimes you just don't know...
Check it out! http://bit.ly/2rFvaBS
xit("can start with an xit", function(){
expect(true).toBe(true);
});
it("is a pending test if there is no callback function");
it("is pending if the pending function is invoked inside the callback", function(){
expect(2).toBe(2);
pending();
});
describe("Earth", function(){
it('is round and has a method to check what number it is from the sun', function(){
expect(earth.isRound()).toBe(true);
expect(earth.howFarFromSun).toBe(jasmine.any(Function);
expect(earth.howFarFromSun()).toBe(3);
});
});
Not great
You do not always need a single expect per it block, if you are testing the same piece of functionality
describe("Earth", function(){
it('is round', function(){
expect(earth.isRound()).toBe(true);
});
it('has a method to check what number it is from the sun', function(){
expect(earth.howFarFromSun).toBe(jasmine.any(Function);
expect(earth.howFarFromSun()).toBe(3);
});
});
Better
function add(a,b,c){
return a+b+c;
}
describe("add", function(){
var addSpy, result;
beforeEach(function(){
addSpy = spyOn(window, 'add');
result = addSpy();
})
it("is can have params tested", function(){
expect(addSpy).toHaveBeenCalled();
});
});
describe("add", function(){
var addSpy, result;
beforeEach(function(){
addSpy = spyOn(window, 'add');
result = addSpy(1,2,3);
});
it("is can have params tested", function(){
expect(addSpy).toHaveBeenCalled();
expect(addSpy).toHaveBeenCalledWith(1,2,3);
});
});
function add(a,b,c){
return a+b+c;
}
describe("add", function(){
var addSpy, result;
beforeEach(function(){
addSpy = spyOn(window, 'add').and.callThrough();
result = addSpy(1,2,3);
})
it("can have a return value tested", function(){
expect(result).toEqual(6);
});
});
function add(a,b,c){
return a+b+c;
}
describe("add", function(){
var addSpy, result;
beforeEach(function(){
addSpy = spyOn(window, 'add').and.callThrough();
result = addSpy(1,2,3);
})
it("is can have params tested", function(){
expect(addSpy.calls.any()).toBe(true);
expect(addSpy.calls.count()).toBe(1);
expect(result).toEqual(6);
});
});
function add(a,b,c){
return a+b+c;
}
describe("a simple setTimeout", function(){
var sample;
beforeEach(function() {
sample = jasmine.createSpy("sampleFunction");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("is only invoked after 1000 milliseconds", function(){
setTimeout(function() {
sample();
}, 1000);
jasmine.clock().tick(999);
expect(sample).not.toHaveBeenCalled();
jasmine.clock().tick(1);
expect(sample).toHaveBeenCalled();
});
});
describe("a simple setTimeout", function(){
var sample;
beforeEach(function() {
sample = jasmine.createSpy("sampleFunction");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
});
describe("a simple setInterval", function(){
var dummyFunction;
beforeEach(function() {
dummyFunction = jasmine.createSpy("dummyFunction");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("checks to see the number of times the function is invoked", function(){
setInterval(function() {
dummyFunction();
}, 1000);
jasmine.clock().tick(999);
expect(dummyFunction.calls.count()).toBe(0);
jasmine.clock().tick(1000);
expect(dummyFunction.calls.count()).toBe(1);
jasmine.clock().tick(1);
expect(dummyFunction.calls.count()).toBe(2);
});
});
describe("a simple setInterval", function(){
var dummyFunction;
beforeEach(function() {
dummyFunction = jasmine.createSpy("dummyFunction");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
});
function getUserInfo(username){
return $.getJSON('https://api.github.com/users/' + username);
}
describe("#getUserInfo", function(){
it("returns the correct name for the user", function(done){
getUserInfo('elie').then(function(data){
expect(data.name).toBe('Elie Schoppik');
done();
});
});
});
notice 'done' being passed and used in the callback function
Green
Red
Refactor
A subset of TDD
Not mutually exclusive with TDD
Involves being verbose with our style and describing the behavior of the functionality
Helpful when testing the design of the software
Integration tests
Stress tests
Acceptance tests