Часть I – Тестирование модулей – как ребенок



Часть I – Тестирование модулей – как ребенок

0 0


fdconf-tests-slides

Слайды доклада про тестирование приложений на FDConf

On Github Zhigalov / fdconf-tests-slides

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Часть I

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

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

FDConf 2016            -> #Fdconf2016
Тестов много не бывает -> #ТестовМногоНеБывает
        
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 FDConf');
        actual.should.be.equal('#HelloFdconf');
    });
});

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

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

describe('Twitter signup', function () {
   it('should alert when`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)
    

Часть III

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

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

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

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

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"]',
                       'Слайды тестирование FDConf');
      browser.submitForm('form[action="/search"]');
      var repoName = browser.getText('h3');
      repoName.should.be
            .equal('Zhigalov/fdconf-tests-slides');
   });
});
            wdio wdio.conf.js
        

DEMO

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

В IDE

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

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

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

Travis CI

└── .travis.yml

language: node_js
node_js:
    - "4.1"
        
└── .travis.yml
└── package.json
        
{
    "scripts": {
        "test": "mocha test"
    }
}
        

DEMO

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

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

Подменяйте зависимости

var translate = require('translate');
        
function hashTagGenerator(words) {
    return '#' + translate(words)
        .split(/\s+/)
        .map(normalizeWord)
        .join('');
}
        
it('should translate hashTag', function (){
    function translateMock () {
        return 'Hello, FDConf!';
    }
    mockery.registerMock('translate', translateMock);
    mockery.enable();
 
    var hashTag = require('../src/hashTagGenerator.js');
    var actual = hashTag('Привет, FDConf!');
    actual.should.be.equal('#HelloFDConf');
});

Первый шаг

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

Не убедил?

nock

var nock = require('nock');

nock('https://translate.com')
    .get('/text=Привет+FDConf')
    .reply(200, 'Hello FDConf);
        

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

приятно

удобно

рабочий код

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

уверенность

Спасибо!

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