«Если у вас нету тестов ...»

Сергей Жигалов

Яндекс


function(words) {
    return '#' + words
        .split(/\s+/)
        .map(normalizeWord)
        .join('');
}
        

Это тоже удовольствие!


function() {
    var actual = hashTag('hello DUMP');

    actual.should.be.equal('#HelloDump');
}
        

Тесты - это продуктивно

Придает уверенности

Old web application

Тесты - это продуктивно

Придает уверенности

New web application

Тесты - это продуктивно

Придает уверенности

Помогает рефакторить

Обновлять зависимости

Быть командой

Живая документация

Часть I

Тестирование модулей

Билдер хештегов


DUMP 2016              -> #Dump2016
Тестов много не бывает -> #ТестовМногоНеБывает
        

function hashTagGenerator(words) {
    return '#' + words
            .split(/\s+/)
            .map(normalizeWord)
            .join('');
}
        

function normalizeWord(word) {
    return word.charAt(0).toUpperCase() +
        word.toLowerCase().slice(1);
}
        

module.exports = hashTagGenerator;
        

nodejs.org

$ npm install mocha

app/
└── src
    └── hashTagGenerator.js
    └── ...
└── test
    └── hashTagGenerator-test.js
    └── ...
        


var hashTag = require('../src/hashTagGenerator.js');
        
 
describe('Hash tag generator', function () {
    it('should normalize words', function () {
        var actual = hashTag('hello DUMP');
 
        actual.should.be.equal('#HelloDump');
    });
});

chaijs


$ npm install chai
        


var chai = require('chai');
chai.should();
         

$ mocha test
        

  Hash tag generator
     should normalize words

1 passing (3ms)

как ребенок

А что, если...


it('should clean extra symbols', function () {
    var actual = hashTag('    #@mu-ha-ha!!!');

    actual.should.be.equal('#MuHaHa');
});
        
  Hash tag generator
     should start with #
     should concat words
     should normalize words
    1) should clean extra symbols

3 passing (13ms)
1 failing

1) Hash tag generator should clean extra symbols:

    AssertionError: expected '##@%mu-ha-ha!'
                    to equal '#MuHaHa'
    + expected - actual

    -##@%mu-ha-ha!
    +#MuHaHa
    

function hashTagGenerator(words) {
    return '#' + words
            .split(/\s+/)
            .map(normalizeWord)
            .join('');
}
        

function hashTagGenerator(words) {
    return '#' + words
            .split(/[^\wа-яё]/i)
            .map(normalizeWord)
            .join('');
}
        

... под другим углом

Часть II

Тетирование клиентского кода

DEMO


describe('Twitter signup', function () {
    it('should alert when enter `twitterok`', function () {
        inputTextTo($('#full-name'), 'twitterok');

        $('.notwitter').is(':visible').should.be.true;
    });
});
        

function inputTextTo($el, text) {
    $el.val(text).trigger('input');
}
        


function inputTextTo($el, text) {
    $el.focus();
    document.execCommand(
        'insertText', false, text);
}
        

<head>


<!-- подключаем стили Mocha -->
<link
    rel="stylesheet"
    href="./node_modules/mocha/mocha.css">
        

<body>


<!-- подключаем библиотеки -->
<script src="./node_modules/mocha/mocha.js"></script>
<script src="./node_modules/chai/chai.js"></script>
        

<!-- настраиваем Mocha -->
<script> mocha.setup('bdd'); </script>
        

<!-- подключаем файл с тестами -->
<script src="/form-test.js"></script>
        

<!-- элемент в котором будут результаты тестов -->
<div id="mocha"></div>
        

<!-- запускаем Mocha -->
<script> mocha.run(); </script>
        

DEMO

Автоматизировать?

PhantomJS

PhantomJS is a headless WebKit scriptable with a JavaScript API.

mocha-phantomjs


            $ npm install -g mocha-phantomjs
        

Адаптируем запуск


<!-- запускаем Mocha -->
<script>
    window.mochaPhantomJS ?
        mochaPhantomJS.run() :
        mocha.run();
</script>
        
$ mocha-phantomjs twitter-signup.html

  Twitter signup
     should no error when input is empty
     should no error when input `teremok`
     should show error when input `twitterok`

  3 passing (14ms)
    
Karma

Часть III

Тестирование сценариев

Перейти на главную страницу https://github.com


В строке поиска набрать "Слайды тестирование DUMP"


Проверить что репозиторий есть в списке

WebdriverIO


            $ npm install webdriverio
        

            $ wdio config
        


wdio.conf.js

describe('GitHub', function () {
   it('search', function () {
      browser.url('http://github.com');
      browser.setValue('input[name="q"]',
                       'Слайды тестирование DUMP');
      browser.submitForm('form[action="/search"]');
      var repoName = browser.getText('h3.repo-list-name');
 
      repoName.should.be.equal('Zhigalov/dump-tests-slides');
   });
});
            wdio wdio.conf.js
        
Run webdriver

DEMO

Запускайте чаще

В IDE

При сохранении файла

Перед коммитом и пушем (husky)

CI сервер ( TeamCity, drone.io, Travis CI, ...)

Travis CI


# .travis.yml

language: node_js
node_js:
    - "4.1"
        

// package.json

{
    "scripts": {
        "test": "mocha test"
    }
}
        

DEMO

Информировать команду

  • Письмо
  • SMS сообщение
  • Или как-то еще... ;)

Первый шаг

Пишите тесты сразу

Не убедил?

web application

nock


var nock = require('nock');

nock('https://api.github.com')
    .get('/users/zhigalov')
    .query(true)
    .reply(200, {
        "name": "Sergey Zhigalov",
        "company": "Яндекс",
        "email": "sergey.zhigalov@gmail.com"
    });
        

var request = require('request');
var url = 'https://api.github.com/users/zhigalov';

request(url, function (error, res, body) {
    console.log(body);
});
        


{
    "name": "Sergey Zhigalov",
    "company": "Яндекс",
    "email": "sergey.zhigalov@gmail.com"
}
        

Тестирование - это:

приятно

удобно

рабочий код

удовольствие

уверенность

Спасибо!


speaker.should.deep.equal({
    face: My face!,
    name: 'Сергей',
    twitter: '@sergey_zhigalov',
    email: 'zhigalov@yandex-team.ru'
});