47
Mocha Покрой свой фронт-енд по полной

2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

  • Upload
    -

  • View
    89

  • Download
    0

Embed Size (px)

DESCRIPTION

Тестирование фронтенда - непростая задача. Mocha - один из подходов к ее решению.

Citation preview

Page 1: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

MochaПокрой свой фронт-енд по полной

Page 2: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

О себеВладислав Безверхий, web-developer, A2 Design

Интересуюсь IT с 2005 годаПишу всякие штуки для себя с 2009 годаРаботаю в IT с 2012 года

Увлекаюсь музыкой, играю\вожу D&D. Люблю маму, папу, фракталы, парадоксы и функциональное программирование.

Page 3: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Жизнь без тестов● Нельзя с уверенностью сказать что код работает.● Каждая новая фича - беда для разработчика● Боишься регрессий как огня● При удачном стечении обстоятельств может сломаться production и

разбиться сердце заказчика \ product owner’а

Page 4: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
Page 5: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Решение?● соблюдение принципов разработки (например

KISS/DRY)● Модульное тестирование (Unit tests)● Функциональное тестирование● соблюдение code-styles● применение методологии разработки

Page 6: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

А что с фронт-ендом?

● Зависимость от сервера● Зависимость от браузера● DOM дерево - не всегда твой друг● Иногда бывает callback hell● Можно ловкой глобальной переменной

сломать всё

Page 7: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
Page 8: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Что из этого можно решить с помощью Unit-тестов?● Зависимость от сервера - mock объекты● Зависимость от браузера - можно прогонять тесты в

разных браузерах.● Операции над DOM деревом можно тестировать● Сallback hell - с помощью spy функций● Глобальная переменная быстро проявит себя в

хорошо написанных тестах

Page 9: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Средства тестирования

Jasmine JS

● полная поддержка BDD● methods chaining● написана в первую очередь для браузера● имеются пакеты для python и ruby● дружит с Sinon

Page 10: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Средства тестирования

Mocha js

● Поддерживает BDD и TDD● Написана с поддержкой браузера и Node JS● Возможность подключать разные библиотеки для asserts● Дружит с Sinon и Chai

Page 11: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Toolkit

● Mocha● Chai● Sinon

Page 12: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Toolkit

● Mocha - запускает тесты● Chai - предоставляет API● Sinon - mock объекты

Page 13: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Подключение

\> npm install mocha

\> npm install chai

\> npm install sinon

Page 14: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Подключаем в браузер (Mocha + Chai)<head>

<title>Express Tests</title>

<link rel="stylesheet" href="/stylesheets/tests/mocha.

css">

<script src="/javascripts/mocha.js"></script>

<script src="/javascripts/chai.js"></script>

<script src=”/javascripts/chai.js”></script>

</head>

Page 15: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Пишем первый тестvar should = chai.expect;

describe('Array', function() {

describe('#indexOf()', function(){

it('should return -1 when the value is not present', function(){

should([1, 3, 4].indexOf(5)).equal(-1);

should([1, 3, 4].indexOf(0)).equal(-1);

});

});

});

Page 16: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Тестируем свой кодvar MapHandler = function() {

var self = this;

self.squareSide = 0.11;

self.init();

};

MapHandler.prototype.coordsPolynome = function(x) {

x = Math.abs(x);

return 1.75477 * Math.pow(10, -6) * Math.pow(x, 3) -0.000365418

* Math.pow(x, 2) + 0.00845663 * x + 0.954619;//

};

Page 17: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Тестируем свой код

describe('coordsPolynome', function() {

it('should be clear', function() {

assert.equal(MapHandler.coordsPolynome(50),MapHandler.coordsPolynome(50));

assert.equal(MapHandler.coordsPolynome(-10),MapHandler.coordsPolynome(10));

});

});

Page 18: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Запускаем тесты

<script>

mocha.setup('bdd');

mocha.bail(false);

mocha.run();

</script>

</body>

Page 19: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
Page 20: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

А что еще дает нам chai?

Page 21: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Chai plugins

● Для фреймворков● Для jQuery● Для всевозможных изменений (DOM,

promises etc.)● Можно писать свои - есть API

Page 22: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Немного о Sinon

● Function Spies● Stubs● Fake Ajax● Fake XMLHttpRequest● Fake Server● Faking Time

Page 23: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon - simplify your testing

● Framework- agnostic (поддерживает Jasmine, Mocha)

● Нет зависимостей● Можно использовать как на сервере так и

в браузере

Page 24: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon SpiesПроблемы:● Отслеживание вызовов callback’ов● Отслеживание контекста внутри callback’ов● Отслеживание переменных переданных в callback● Отслеживание влияния callback’а на внешний scope

Page 25: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

function once(fn) {

var returnValue, called = false;

return function () {

if (!called) {

called = true;

returnValue = fn.apply(this, arguments);

}

return returnValue;

};

}

Page 26: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("calls the original function", function () {

var callback = sinon.spy();

var proxy = once(callback);

proxy();

assert(callback.called);

});

Page 27: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("calls the original function only once", function () {

var callback = sinon.spy();

var proxy = once(callback);

proxy();

proxy();

assert(callback.calledOnce);

// ...or:

// assert.equals(callback.callCount, 1);

});

Page 28: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("calls original function with right this and args", function()

{

var callback = sinon.spy();

var proxy = once(callback);

var obj = {};

proxy.call(obj, 1, 2, 3);

assert(callback.calledOn(obj));

assert(callback.calledWith(1, 2, 3));

});

Page 29: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon - Mocks

● Тестируемая функция зависит от какого либо внешнего API (например фреймворка)

● Тестируема функция зависит от внешнего объекта

Page 30: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("returns the return value from the original function",

function () {

var myAPI = { method: function () {} };

var mock = sinon.mock(myAPI);

mock.expects("method").once().returns(42);

var proxy = once(myAPI.method);

assert.equals(proxy(), 42);

mock.verify();

});

Page 31: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon - Stubs

Проблемы:● Вызов функций за пределами теста● Дублирование тестов● Результат вызываемой функции зависит

от времени\внешних условий● Функция является замыканием

Page 32: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("returns the return value from the original function",

function () {

var stub = sinon.stub().returns(42);

var proxy = once(stub);

assert.equals(proxy(), 42);

});

Page 33: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon - Fake XHR

Проблемы:● Время отклика замедляет тестирование● Сервер может быть не всегда доступен● Запрос формируется динамически● Выполнение запроса повлечет изменение

данных на сервере

Page 34: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

var xhr, requests;

before(function() {

xhr = sinon.useFakeXMLHttpRequest();

requests = [];

xhr.onCreate = function (req) { requests.push(req); };

});

after(function() {

// Like before we must clean up when tampering with globals.

xhr.restore();

});

Page 35: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("makes a GET request for todo items", function () {

getSomething(42, sinon.spy());

assert.equal(requests.length, 1);

assert.equal(requests[0].url, "/something/42");

});

Page 36: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon (Fake Server) - testing

Проблемы:● Недоступность\отсутствие сервера● Время отклика● Несоответствие API сервера текущей

спецификации● Запросы влияют на данные сервера

Page 37: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

var server;

beforeEach(function () { server = sinon.fakeServer.create(); });

afterEach(function () { server.restore(); });

Page 38: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("returns ok", function() {

var callback = sinon.spy();

getSomething(42, callback);

// This is part of the FakeXMLHttpRequest API

server.requests[0].respond(

200,

{ "Content-Type": "application/json" },

JSON.stringify([{ id: 1, text: "Provide examples", done:

true }])

);

assert.equal(200, server.requests[0].status);

})

Page 39: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("calls callback with deserialized data", function () {

var callback = sinon.spy();

getTodos(42, callback);

// This is part of the FakeXMLHttpRequest API

server.requests[0].respond(

200,

{ "Content-Type": "application/json" },

JSON.stringify([{ id: 1, text: "Provide examples", done:

true }])

);

assert(callback.calledOnce);

});

Page 40: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Sinon (Timers) - prepare

Проблемы:● Может сильно замедлить прохождение

тестов● Изменение состояния объектов в рамках

setInterval● Очень не удобно отлаживать

Page 41: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

function throttle(callback) {

var timer;

return function () {

clearTimeout(timer);

var args = [].slice.call(arguments);

timer = setTimeout(function () {

callback.apply(this, args);

}, 100);

};

}

Page 42: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

var clock;

before(function () { clock = sinon.useFakeTimers(); });

after(function () { clock.restore(); });

Page 43: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

it("calls callback after 100ms", function () {

var callback = sinon.spy();

var throttled = throttle(callback);

throttled();

clock.tick(99);

assert(callback.notCalled);

clock.tick(1);

assert(callback.calledOnce);

assert.equal(new Date().getTime(), 100);

}

Page 44: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Смотреть тесты фронтенда в консоли?

\> npm install mocha-phantomjs

Page 45: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Смотреть тесты фронтенда в консоли?

<script>

if (window.mochaPhantomJS) { mochaPhantomJS.run(); }

else { mocha.run(); }

</script>

Page 46: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

Смотреть тесты фронтенда в консоли? <script>

if (window.mochaPhantomJS) { mochaPhantomJS.run(); }

else { mocha.run(); }

</script>

\> npm install mocha-phantomjs

$ mocha-phantomjs -R dot /test/file.html

$ mocha-phantomjs http://testserver.com/file.html

$ mocha-phantomjs -s localToRemoteUrlAccessEnabled=true -s webSecurityEnabled=false

http://testserver.com/file.html

$ mocha-phantomjs -p ~/bin/phantomjs /test/file.html

Page 47: 2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной

@rabbiabram

Спасибо за внимание