50
В поисках качества JavaScript : модульное тестирование Анна Хабибуллина DA-14 / da-14.com [email protected] akhabibullina _khabibullina

Js fwdays unit tesing javascript(by Anna Khabibullina)

Embed Size (px)

DESCRIPTION

See video from JS Frameworks Day, April 2014 https://www.youtube.com/watch?v=edOIMiQFZ2w&list=UU3NDbeN0Jq_InNAhiJtvHcQ

Citation preview

Page 1: Js fwdays unit tesing javascript(by Anna Khabibullina)

В поисках качества JavaScript:модульное тестирование

Анна ХабибуллинаDA-14 / da-14.com

[email protected]

akhabibullina

_khabibullina

Page 2: Js fwdays unit tesing javascript(by Anna Khabibullina)

SAY HI

Page 3: Js fwdays unit tesing javascript(by Anna Khabibullina)

ZE QUALITYS?

“Any feature without a test doesn’t exist”

Steve Loughran HP Laboratories

Page 4: Js fwdays unit tesing javascript(by Anna Khabibullina)

AGENDA

Unit Testing Concept

Pros & Cons

Basic Terms & Structure

TDD &/vs. BDD

Tools & Libraries

Unit Testing Specifics

in JavaScript

Best Practices

Page 5: Js fwdays unit tesing javascript(by Anna Khabibullina)

UNIT TESTING CONCEPT

Unit testing is a method by which individual

units of source code are tested to determine

if they are fit for use.

Page 6: Js fwdays unit tesing javascript(by Anna Khabibullina)

WHY UNIT TESTING?

Unit tests find problems early in the

development cycle (TDD & BDD)

Refactoring

Integration

Documentation

Better design

Page 7: Js fwdays unit tesing javascript(by Anna Khabibullina)

IS UNIT TESTING A GOOD INVESTMENT?

slow down the development process

share the same blind spots with the code

doesn’t prove that they’re compatible with

one another or configured correctly

Page 8: Js fwdays unit tesing javascript(by Anna Khabibullina)

BASIC TERMS

Page 9: Js fwdays unit tesing javascript(by Anna Khabibullina)

In simple words, the goal of assertion is to

forcefully define if the test fails or passes.

STATEMENT PASSES FAILS

x = 1 assert(x > 0) assert(x < 0)

expect(4+5).to.equal(9);

ASSERTION

Page 10: Js fwdays unit tesing javascript(by Anna Khabibullina)

function initialize() {

// The initialization was successful.

return true;

}

Given the function initialize():

ASSERTION: EXAMPLE

Page 11: Js fwdays unit tesing javascript(by Anna Khabibullina)

ASSERTION: EXAMPLE

var isInitialized = initialize();

TDD assert.isTrue(isInitialized)

BDD expect(isInitialized).to.be.true

Check that function initialize() returns true

when called.

Page 12: Js fwdays unit tesing javascript(by Anna Khabibullina)

FIXTURE

A test fixture is a fixed state of the software

under test used as a baseline for running

tests.

In JavaScript for client side:

simulate AJAX responses;

loading known set of data such as html

objects.

Page 13: Js fwdays unit tesing javascript(by Anna Khabibullina)

FIXTURE: EXAMPLE

Require the piece of markup stored in

myfixturemarkup.html file before each test:

beforeEach(function() {

loadFixtures('myfixturemarkup.html');

});

Page 14: Js fwdays unit tesing javascript(by Anna Khabibullina)

STUB

Method stubs

are functions

with pre-

programmed

behavior.

Page 15: Js fwdays unit tesing javascript(by Anna Khabibullina)

STUB: EXAMPLE

Forcing a method to throw an error in order

to test error handling.

var fn = foo.stub().throws(Error);

expect(fn).to.throw(Error);

Page 16: Js fwdays unit tesing javascript(by Anna Khabibullina)

SPY

A test spy is a

function that

records

arguments,

return value, the

value of this and

exception thrown

(if any) for all its

calls.

Page 17: Js fwdays unit tesing javascript(by Anna Khabibullina)

SPY: EXAMPLE

Test that a function cursor.hide() has been

only called once, and only once.

sinon.spy(cursor, "hide");

TDD sinon.assert.calledOnce(cursor.hide)

BDD expect(cursor.hide.calledOnce).to.be.true

Page 18: Js fwdays unit tesing javascript(by Anna Khabibullina)

MOCK

Mocks are fake objects with pre-

programmed behavior (like stubs) and

pre-programmed expectations.

They are like both stubs and spies – in

one.

Page 19: Js fwdays unit tesing javascript(by Anna Khabibullina)

MOCK: EXAMPLE

Create an expectation that jQuery.each is

called once, and only once, and also

instructs the mock to behave as we pre-

define.

var mock = sinon.mock(jQuery);

Page 20: Js fwdays unit tesing javascript(by Anna Khabibullina)

MOCK: EXAMPLE

#1 – which method?

#2 – how many times it is called?

#3 – what are the arguments when the

method called?

#4 – what the method returns?

Page 21: Js fwdays unit tesing javascript(by Anna Khabibullina)

TEST DRIVEN DEVELOPMENT(TDD)

TDD is a software

development

process that…

I’ll tell you the rest

Page 22: Js fwdays unit tesing javascript(by Anna Khabibullina)

WHAT ARE THESE BDD?

Page 23: Js fwdays unit tesing javascript(by Anna Khabibullina)

ALRIGHT, WHAT IS BDD YOU ASK?

Terminology:

TDD BDD

Test Example

Assertion Expectation

Unit Behavior

Page 24: Js fwdays unit tesing javascript(by Anna Khabibullina)

BASIC STRUCTURE

#1. Setup/BeforeEach/Before

#2. Prepare an input

#3. Call a method

#4. Check an output

#5. Tear down/AfterEach/After

Page 25: Js fwdays unit tesing javascript(by Anna Khabibullina)

#1. Setup / Before

before(function(done) {

// Create a basic document.

document = jsdom.jsdom();

window = document.parentWindow;

done();

});

BASIC STRUCTURE: EXPLAINED

Page 26: Js fwdays unit tesing javascript(by Anna Khabibullina)

Before / BeforeEach

before(function() { console.log(‘before test’); });

test(‘first test’, function() { console.log(‘first test’); });

test(‘second test’, function() { console.log(‘second test’);});

afterEach(function() { console.log(‘after each test’); });

Result

before test

first test

after each test

second test

after each test

BASIC STRUCTURE: EXPLAINED

Page 27: Js fwdays unit tesing javascript(by Anna Khabibullina)

BASIC STRUCTURE: EXPLAINED

it('should initialize cursor if zoom level >= minimum zoom

level.',

#2. Prepare an input and predicted result.

var minZoomLevel = 1;

var zoomLevel = minZoomLevel + 0.1;

var expectedCursor = {‘color’: ‘white’, ‘height’: … };

#3. Call a method.

var actualCursor = cursor.init(zoomLevel);

#4. Check an output.

expect(actualCursor).to.deep.equal(expectedCursor);

done();

});

function(done) {

Page 28: Js fwdays unit tesing javascript(by Anna Khabibullina)

BASIC STRUCTURE: EXPLAINED

it('should initialize cursor if zoom level >= minimum zoom

level.',

#2. Prepare an input and predicted result.

var minZoomLevel = 1;

var zoomLevel = minZoomLevel + 0.1;

var expectedCursor = {‘color’: ‘white’, ‘height’: … };

#3. Call a method.

var actualCursor = cursor.init(zoomLevel);

#4. Check an output.

expect(actualCursor).to.deep.equal(expectedCursor);

done();

});

function(done) {

Page 29: Js fwdays unit tesing javascript(by Anna Khabibullina)

BASIC STRUCTURE: EXPLAINED

it('should initialize cursor if zoom level >= minimum zoom

level.',

#2. Prepare an input and predicted result.

var minZoomLevel = 1;

var zoomLevel = minZoomLevel + 0.1;

var expectedCursor = {‘color’: ‘white’, ‘height’: … };

#3. Call a method.

var actualCursor = cursor.init(zoomLevel);

#4. Check an output.

expect(actualCursor).to.deep.equal(expectedCursor);

done();

});

function(done) {

Page 30: Js fwdays unit tesing javascript(by Anna Khabibullina)

BASIC STRUCTURE: EXPLAINED

it('should initialize cursor if zoom level >= minimum zoom

level.',

#2. Prepare an input and predicted result.

var minZoomLevel = 1;

var zoomLevel = minZoomLevel + 0.1;

var expectedCursor = {‘color’: ‘white’, ‘height’: … };

#3. Call a method.

var actualCursor = cursor.init(zoomLevel);

#4. Check an output.

expect(actualCursor).to.deep.equal(expectedCursor);

done();

});

function(done) {

Page 31: Js fwdays unit tesing javascript(by Anna Khabibullina)

#5. TearDown / After

after(function(done) {

// Remove global objects document.

document = null;

window = null;

done();

});

BASIC STRUCTURE: EXPLAINED

Page 32: Js fwdays unit tesing javascript(by Anna Khabibullina)

OUTPUT

Page 33: Js fwdays unit tesing javascript(by Anna Khabibullina)

<testsuite name="Macchiato Tests" tests="13"

failures="0" errors="0" skipped="0"

timestamp="Mon, 02 Dec 2013 11:08:09 GMT"

time="0.114">

<testcase classname = "cursor #init ()"

name = "should initialize cursor if

zoom level &gt; minimum zoom level."

time="0.004"/>

</testsuite>

OUTPUT: SUCCESS

Page 34: Js fwdays unit tesing javascript(by Anna Khabibullina)

<failure classname="cursor #init()"

name="should initialize cursor if zoom level

&gt; minimum zoom level." time="0"

message="Cannot read property 'show' of

undefined"><![CDATA[TypeError: Cannot read

property 'show' of undefined

// ..... Exception Stack Trace .....

</failure>

OUTPUT: FAILURE

Page 35: Js fwdays unit tesing javascript(by Anna Khabibullina)

TOOLS

Page 36: Js fwdays unit tesing javascript(by Anna Khabibullina)

TOOLS

> 40 frameworks & libraries

qUnit(TDD) light-weight TDD framework

Jasmine(BDD) flexible BDD framework

Mocha / Karma test runner for async code

+ Chai TDD / BDD assertion library

+ Sinon test spies, stubs & mocks

Page 37: Js fwdays unit tesing javascript(by Anna Khabibullina)

ENTIRE SPACE OF FRAMEWORKS…

Page 38: Js fwdays unit tesing javascript(by Anna Khabibullina)

HOW DO I UNIT TEST Known Frameworks / Libraries?

What to test? What to use?

Angular, React, Flight Karma + Jasmine

Backbone qUnit

Ember Karma + qUnit (ember-app-kit)

ExtJs Jasmine, Siesta (UI)

TypeScript tsUnit

CoffeeScript qUnit

Dart Unittest, Hop and Drone.io

NodeJs expresso and vows, Nodeunit

Page 39: Js fwdays unit tesing javascript(by Anna Khabibullina)

TOOLS: WHAT WE USE

Run UT: Mocha

Run UT in parallel: Macchiato

Assert/Expect: Chai

W3C DOM in JavaScript: Jsdom

Mock, spy, stub: Sinon

Code coverage tool: None

Routine automation: make/Grunt

Page 40: Js fwdays unit tesing javascript(by Anna Khabibullina)

TOOLS: WHAT WE USE

Page 41: Js fwdays unit tesing javascript(by Anna Khabibullina)

TOOLS: WHAT WE USE

Project unit tested like a dream ♥

Page 42: Js fwdays unit tesing javascript(by Anna Khabibullina)

UNIT TESTING SPECIFICS IN JAVASCRIPT

UI

Load fake data via “fixtures”

Jsdom(W3C JavaScript implementation)

Page 43: Js fwdays unit tesing javascript(by Anna Khabibullina)

UNIT TESTING SPECIFICS IN JAVASCRIPT

AJAX

Stub jQuery.ajax

Fake XMLHttpRequest(XMLHTTP ActiveXObject)

Fake server

Page 44: Js fwdays unit tesing javascript(by Anna Khabibullina)

UNIT TESTING SPECIFICS IN JAVASCRIPT

3rd-party scripts

Stubbing jQuery plugin functions

(mock jQuery.fn)

Page 45: Js fwdays unit tesing javascript(by Anna Khabibullina)

UNIT TESTING SPECIFICS IN JAVASCRIPT

Dependency Injection

Mocking deps in RequireJs sucks hard!

Squire.js lib / testr.js

Page 46: Js fwdays unit tesing javascript(by Anna Khabibullina)

UNIT TESTING SPECIFICS IN JAVASCRIPT

NodeJs

Server-side specifics

rewire: node.js dependency injection

Page 47: Js fwdays unit tesing javascript(by Anna Khabibullina)

BEST PRACTISES

Fast

Isolated

Consistent

Responsibility

Self-descriptive

No exception Handling

Use assertions when needed

Page 48: Js fwdays unit tesing javascript(by Anna Khabibullina)

WRAPPING UP

Each test verifies a small chunk of code

Unit tests work best in isolation

Mocks, stubs and spies help to isolate test

Don’t test everything but write many tests

> 40 tools are available to ease unit testing

experience, so CHOOSE YOUR OWN!

Page 49: Js fwdays unit tesing javascript(by Anna Khabibullina)

SHWEEET

Page 50: Js fwdays unit tesing javascript(by Anna Khabibullina)

ありがとう