JS Frameworks Day April,26 of 2014

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

description

Unit Testing in Javascript The way to quality product isn't easy or simple but it is reachable. One of the key things to do is unit testing. What, when and how to do it --> read in the presentation. See more details here: http://www.slideshare.net/AnnaKhabibullina/jsfwdays-2014unittesingjavascriptv4-33966202 Read about this and other techtalks @ DA-14 in our blog: http://da-14.com/our-blog/

Transcript of JS Frameworks Day April,26 of 2014

Page 1: JS Frameworks Day April,26 of 2014

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

[email protected]

akhabibullina

_khabibullina

Page 2: JS Frameworks Day April,26 of 2014

ZE QUALITYS?

“Any feature without a test doesn’t exist”

Steve Loughran HP Laboratories

Page 3: JS Frameworks Day April,26 of 2014

AGENDA

Unit Testing Concept Pros & Cons Basic Terms & Structure TDD &/vs. BDD Tools & Libraries Unit Testing Specifics in JavaScript Best Practices

Page 4: JS Frameworks Day April,26 of 2014

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 5: JS Frameworks Day April,26 of 2014

WHY UNIT TESTING?

Unit tests find problems early in the development cycle (TDD & BDD)

Refactoring

Integration

Documentation

Better design

Page 6: JS Frameworks Day April,26 of 2014

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 7: JS Frameworks Day April,26 of 2014

BASIC TERMS

Page 8: JS Frameworks Day April,26 of 2014

In simple words, the goal of assertion is to forcefully define if the test fails or passes.

STATEMENT PASSES FAILSx = 1 assert(x > 0) assert(x < 0)

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

ASSERTION

Page 9: JS Frameworks Day April,26 of 2014

function initialize() {

// The initialization was successful. return true;}

Given the function initialize():

ASSERTION: EXAMPLE

Page 10: JS Frameworks Day April,26 of 2014

ASSERTION: EXAMPLE

var isInitialized = initialize();

TDD assert.isTrue(isInitialized)BDD expect(isInitialized).to.be.true

Check that function initialize() returns true when called.

Page 11: JS Frameworks Day April,26 of 2014

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 12: JS Frameworks Day April,26 of 2014

FIXTURE: EXAMPLE

Require the piece of markup stored in myfixturemarkup.html file before each test:

beforeEach(function() {

loadFixtures('myfixturemarkup.html');

});

Page 13: JS Frameworks Day April,26 of 2014

STUB

Method stubs are functions

with pre-programmed

behavior.

Page 14: JS Frameworks Day April,26 of 2014

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 15: JS Frameworks Day April,26 of 2014

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 16: JS Frameworks Day April,26 of 2014

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 17: JS Frameworks Day April,26 of 2014

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 18: JS Frameworks Day April,26 of 2014

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 19: JS Frameworks Day April,26 of 2014

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 20: JS Frameworks Day April,26 of 2014

TEST DRIVEN DEVELOPMENT(TDD)

TDD is a software development process that…I’ll tell you the rest

Page 21: JS Frameworks Day April,26 of 2014

WHAT ARE THESE BDD?

Page 22: JS Frameworks Day April,26 of 2014

ALRIGHT, WHAT IS BDD YOU ASK?

Terminology:

TDD BDDTest ExampleAssertion ExpectationUnit Behavior

Page 23: JS Frameworks Day April,26 of 2014

BASIC STRUCTURE

#1. Setup/BeforeEach/Before

#2. Prepare an input

#3. Call a method

#4. Check an output

#5. Tear down/AfterEach/After

Page 24: JS Frameworks Day April,26 of 2014

#1. Setup / Before

before(function(done) { // Create a basic document. document = jsdom.jsdom(); window = document.parentWindow; done(); });

BASIC STRUCTURE: EXPLAINED

Page 25: JS Frameworks Day April,26 of 2014

Before / BeforeEachbefore(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 testfirst testafter each testsecond testafter each test

BASIC STRUCTURE: EXPLAINED

Page 26: JS Frameworks Day April,26 of 2014

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 27: JS Frameworks Day April,26 of 2014

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 Frameworks Day April,26 of 2014

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 Frameworks Day April,26 of 2014

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 Frameworks Day April,26 of 2014

#5. TearDown / After

after(function(done) {// Remove global objects document. document = null; window = null;done();

});

BASIC STRUCTURE: EXPLAINED

Page 31: JS Frameworks Day April,26 of 2014

OUTPUT

Page 32: JS Frameworks Day April,26 of 2014

<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 33: JS Frameworks Day April,26 of 2014

<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 34: JS Frameworks Day April,26 of 2014

TOOLS

Page 35: JS Frameworks Day April,26 of 2014

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 36: JS Frameworks Day April,26 of 2014

ENTIRE SPACE OF FRAMEWORKS…

Page 37: JS Frameworks Day April,26 of 2014

HOW DO I UNIT TEST Known Frameworks / Libraries?

What to test? What to use?Angular, React, Flight Karma + JasmineBackbone qUnitEmber Karma + qUnit (ember-app-kit)ExtJs Jasmine, Siesta (UI)TypeScript tsUnitCoffeeScript qUnitDart Unittest, Hop and Drone.io

NodeJs expresso and vows, Nodeunit 

Page 38: JS Frameworks Day April,26 of 2014

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 39: JS Frameworks Day April,26 of 2014

TOOLS: WHAT WE USE

Page 40: JS Frameworks Day April,26 of 2014

TOOLS: WHAT WE USE

Project unit tested like a dream ♥

Page 41: JS Frameworks Day April,26 of 2014

UNIT TESTING SPECIFICS IN JAVASCRIPT

UI

Load fake data via “fixtures”Jsdom(W3C JavaScript implementation)

Page 42: JS Frameworks Day April,26 of 2014

UNIT TESTING SPECIFICS IN JAVASCRIPT

AJAX

Stub jQuery.ajaxFake XMLHttpRequest

(XMLHTTP ActiveXObject)Fake server

Page 43: JS Frameworks Day April,26 of 2014

UNIT TESTING SPECIFICS IN JAVASCRIPT

3rd-party scripts

Stubbing jQuery plugin functions(mock jQuery.fn)

Page 44: JS Frameworks Day April,26 of 2014

UNIT TESTING SPECIFICS IN JAVASCRIPT

Dependency Injection

Mocking deps in RequireJs sucks hard! Squire.js lib /  testr.js 

Page 45: JS Frameworks Day April,26 of 2014

UNIT TESTING SPECIFICS IN JAVASCRIPT

NodeJs

Server-side specificsrewire: node.js dependency injection

Page 46: JS Frameworks Day April,26 of 2014

BEST PRACTISES

FastIsolatedConsistentResponsibilitySelf-descriptiveNo exception HandlingUse assertions when needed

Page 47: JS Frameworks Day April,26 of 2014

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 48: JS Frameworks Day April,26 of 2014

SHWEEET

Page 49: JS Frameworks Day April,26 of 2014

ありがとう