как я подсел на тесты – Делают мой код лучше – Лучшая документация



как я подсел на тесты – Делают мой код лучше – Лучшая документация

0 0


frontend-fellows-slides

Слайды презентации для frontendFellows в Ижевске

On Github Zhigalov / frontend-fellows-slides

как я подсел на тесты

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

Это больно

Делают мой код лучше

Задача

На основании названия поста сгенерировать человеко-понятный урл (slug)

Пример

'Chat Bots for Telegram' // 'chat-bots-for-telegram'
'Tune in to Radio'       // 'tune-in-to-radio'
            

Решение до тестов

function slugGenerator(str) {
    return str
        .toLowerCase()
        .replace(/\s+/g, '-');
}
            
module.exports = slugGenerator;
            
// slugGenerator-test.js
var slugGenerator = require('../src/slugGenerator');
var assert = require('assert');

            
describe('Slug generator', function () {
    it('should cast to lower case', function () {
        var actual = slugGenerator('HellO');
        assert.equal(actual, 'hello');
    });
    it('should replace spaces to `-`', function () {
        var actual = slugGenerator('mu ha ha');
        assert.equal(actual, 'mu-ha-ha');
    });
});

mocha

$ npm install mocha --save-dev
            
$ mocha test
            
  Slug generator
    ✓ should cast to lower case
    ✓ should replace spaces to `-`

  2 passing (8ms)

А что если ...

... передать не строку?

function slugGenerator(str) {
    if (typeof str !== 'string') {
        return;
    }

    return str
        .toLowerCase()
        .replace(/\s+/g, '-');
}
            

А что если ...

... невалидные символы?

function slugGenerator(str) {
    if (typeof str !== 'string') {
        return;
    }
            
    return str
        .toLowerCase()
        .replace(/[^a-z0-9\s]/g, '')
        .replace(/\s+/g, '-');
}

А что если ...

... начинается с пробела?

function slugGenerator(str) {
    if (typeof str !== 'string') {
        return;
    }
            
    return str
        .toLowerCase()
        .replace(/[^a-z0-9\s]/g, '')
        .trim()
        .replace(/\s+/g, '-');
}

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

Лучшая документация

  Comment delete
    ✓ should return 400 when commentId is invalid
    ✓ should return 404 when comment not found
    ✓ should return 403 when comment already removed
    ✓ should return 401 when user not authorized
    ✓ should return 403 when user is banned
    ✓ should return 403 when user not author
    ✓ should success remove comment
    ✓ should decrement commentsCount
    ✓ should decrement replyCount
    - should notify moderator

  9 passing (403ms)
  1 pending

Ускоряют поиск ошибок

  ...

  1049 passing (17s)
  1 failing

  1) Comment delete should return 400 when commentId is invalid:
     Error: expected 401 "Unauthorized", got 400 "Bad Request"
      at Test.assert (tests/v1/comment/comment-delete-test.js:205:15)
      ...

Проверить что переменная posts является массивом
posts instanceof Array // true
            
var posts = '';
assert.ok(posts instanceof Array);
            
1) Assert is array:

  AssertionError: false == true
  + expected - actual

  -false
  +true
var posts = '';
assert.ok(posts instanceof Array,
         'posts is not array');
            
1) Assert is array:

  AssertionError: posts is not array
  + expected - actual

  -false
  +true

chai

var chai = require('chai');
chai.should();
            
var posts = '';
posts.should.be.an.instanceof(Array);
1) Assert is array:

  AssertionError: expected '' to be an
                  instance of Array

Позволяют сделать больше

На основании названия поста на русском языке сгенерировать человеко-понятный урл (slug)
function slugGenerator(str) {
    if (typeof str !== 'string') {
        return;
    }
            
    return translate(str)
        .then(function (result) {
            return result
                .toLowerCase()
                .replace(/[^a-zа-яё0-9\s]/g, '')
                .trim()
                .replace(/\s+/g, '-');
        })

}
it('should translate', function (done) {
    slugGenerator('привет')
        .then(function (actual) {
            actual.should.be.equal('hi');
        })
        .then(done, done);
});
            

nock

it('should translate', function (done) {
    nock('https://translate.yandex.net')
        .get('/api/v1.5/tr.json/translate')
        .query(true)
        .reply(200, {text: ['mu-ha-ha']});
            
    translate('привет')
        .then(function (actual) {
            actual.should.be.equal('mu-ha-ha');
        })
        .then(done, done);
});

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

Держат команду в тонусе

actual

it('should cast to lower case', function () {
    var actual = slugGenerator('HellO');

    actual.should.be.equal('hello');
});

expected

it('should cast to lower case', function () {
    var actual = slugGenerator('HellO');

    var expected = 'hello';
    actual.should.be.equal(expected);
});

три части

Подготовка Действие Проверка
it('should cast to lower case', function () {
    // действие
    var actual = slugGenerator('HellO');
            
    // проверка
    actual.should.be.equal('hello');
});
it('should find all posts', function () {
    // подготовка
    new Post({title: 'first'}).create();
    new Post({title: 'second'}).create();
            
    // действие
    var actual = Posts.findAll();
    // проверка
    actual.should.have.length(2);
});

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

  • В IDE по хоткею
  • При сохранении файла
  • Перед коммитом и пушем
  • CI сервер

Travis

package.json

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

.travis.yml

language: node_js
node_js:
  - "4.1"
            

demo-time

Первый шаг

  • Хелпер
  • Базовая модель
  • Независимый модуль

Спасибо!

@sergey_zhigalov

1
как я подсел на тесты Сергей Жигалов