Download - JS Frameworks Day April,26 of 2014

Transcript
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

ありがとう