Статьи

Использование Nock и TAP для пробного тестирования CouchDB в node.js

Одна из моих первых библиотек node.js была nano : клиент CouchDB без суеты, основанный на супер распространенном запросе . В предвидении это было хорошей идеей, даже несмотря на то, что для CouchDB существует масса клиентов, ни один из них не так прост, как nano, и любой http-клиент, не основанный на запросе, я бы даже не подумал.

Когда вы пишете HTTP-клиент, вам нужно протестировать с одной (или несколькими) конечными точками HTTP. Мне было лень об этом, поэтому я решил указать nano, чтобы он открыл и запускал тесты на реальных HTTP-запросах (даже обнаружил ошибку в node.js, которая теперь исправлена ​​в 0.6+). Это был проблемный, но в целом нормальный подход.

Затем несколько недель назад я начал автоматизировать тесты, используя travis . И сборки начали проваливаться. Чтобы это работало и исправлялись все недостатки подключения к iriscouch, мне понадобился модуль HTTP Mocking.

Кстати, Трэвис очень крутой. Вы должны протестировать все свои библиотеки node.js с ним. Все, что вам нужно сделать, это зайти на сайт, войти в систему с помощью github и поместить файл .travis.yml, подобный этому, в корень вашей библиотеки:

language: "node_js"
  node_js:
    - 0.4
    - 0.6

 
Enter Nock

Нок Педро Тейшейры позволяет вам проводить тестирование по HTTP Mock, сохраняя при этом возможность запускать тесты с реальной конечной точкой http.

Давайте начнем с этого небольшого теста tap sudo npm install tap nano nock:

var nano = require('nano')('http://nodejsbug.iriscouch.com') 
  var test = require('tap').test;
  var db   = nano.use('testing_nock');

  test('Insert a Document Into CouchDB', function(t) {
    t.plan(4);
    nano.db.create('testing_nock', function () {
      db.insert({foo: "bar"},
        function ensure_insert_worked_cb(err, doc) {
          t.notOk(err, 'No errors');
          t.ok(doc.ok, 'Contains ok');
          t.ok(doc.rev, 'Rev exists');
          t.ok(doc.id, 'Id exists');
        });
    });
  });

 Если мы сохраним это в файле test.js, мы сможем запустить тесты и увидеть, что они все работают. Мы даже можем вызвать сценарий с включенной отладкой и проверить поток запросов / ответов HTTP:

$ NANO_ENV=testing node test.js 
  { url: 'http://nodejsbug.iriscouch.com' }
  >>
  { method: 'PUT',
    headers: 
     { 'content-type': 'application/json',
       accept: 'application/json' },
    uri: 'http://nodejsbug.iriscouch.com/testing_nock' }
  <<
  { err: null,
    body: { ok: true },
    headers: 
     { location: 'http://nodejsbug.iriscouch.com/testing_nock',
       date: 'Thu, 01 Dec 2011 16:42:21 GMT',
       'content-type': 'application/json',
       'cache-control': 'must-revalidate',
       'status-code': 201 } }
  >>
  { method: 'POST',
    headers: 
     { 'content-type': 'application/json',
       accept: 'application/json' },
    uri: 'http://nodejsbug.iriscouch.com/testing_nock',
    body: '{"foo":"bar"}' }
  <<
  { err: null,
    body: 
     { ok: true,
       id: 'f191a858a66828d8de66b3c974005346',
       rev: '1-4c6114c65e295552ab1019e2b046b10e' },
    headers: 
     { location: 'http://nodejsbug.iriscouch.com/testing_nock/f191a858a66828d8de66b3c974005346',
       date: 'Thu, 01 Dec 2011 16:42:22 GMT',
       'content-type': 'application/json',
       'cache-control': 'must-revalidate',
       'status-code': 201 } }
  # Insert a Document Into CouchDB
  ok 1 No errors
  ok 2 Contains ok
  ok 3 Rev exists
  ok 4 Id exists

  1..4
  # tests 4
  # pass  4

  # ok

 Таким образом, nano дает вам возможность увидеть весь HTTP-трафик, который он создает и получает. Это здорово, но мне все еще нужно написать код для поддержки этих взаимодействий.

С nock это супер просто:

var nano = require('nano')('http://nodejsbug.iriscouch.com') 
  var nock = require('nock'); // we require nock
  var test = require('tap').test;
  var db   = nano.use('testing_nock');

  nock.recorder.rec();

  test('Insert a Document Into CouchDB', function(t) {
    t.plan(4);
    nano.db.create('testing_nock', function () {
      db.insert({foo: "bar"},
        function ensure_insert_worked_cb(err, doc) {
          t.notOk(err, 'No errors');
          t.ok(doc.ok, 'Contains ok');
          t.ok(doc.rev, 'Rev exists');
          t.ok(doc.id, 'Id exists');
        });
    });
  });

 Запуск тестов возвращает:

  $ node test.js 

  <<<<<<-- cut here -->>>>>>

  nock('nodejsbug.iriscouch.com')
    .put('/testing_nock')
    .reply(412, "{\"error\":\"file_exists\",\"reason\":\"The database could not be created, the file already exists.\"}\n", { server: 'CouchDB/1.1.1 (Erlang OTP/R14B04)',
    date: 'Thu, 01 Dec 2011 17:43:30 GMT',
    'content-type': 'application/json',
    'content-length': '95',
    'cache-control': 'must-revalidate' });

  <<<<<<-- cut here -->>>>>>

  <<<<<<-- cut here -->>>>>>

  nock('nodejsbug.iriscouch.com')
    .post('/testing_nock', "{\"foo\":\"bar\"}")
    .reply(201, "{\"ok\":true,\"id\":\"8b787a6a1c2476ef9a2eed069e000ff0\",\"rev\":\"1-4c6114c65e295552ab1019e2b046b10e\"}\n", { server: 'CouchDB/1.1.1 (Erlang OTP/R14B04)',
    location: 'http://nodejsbug.iriscouch.com/testing_nock/8b787a6a1c2476ef9a2eed069e000ff0',
    date: 'Thu, 01 Dec 2011 17:43:31 GMT',
    'content-type': 'application/json',
    'content-length': '95',
    'cache-control': 'must-revalidate' });

  <<<<<<-- cut here -->>>>>>

  # Insert a Document Into CouchDB
  ok 1 No errors
  ok 2 Contains ok
  ok 3 Rev exists
  ok 4 Id exists

  1..4
  # tests 4
  # pass  4

  # ok

 Итак, теперь все, что нам нужно сделать, это добавить эти nock http mocks и все готово:

var nano = require('nano')('http://nodejsbug.iriscouch.com') 
  var nock = require('nock'); // we require nock
  var test = require('tap').test;
  var db   = nano.use('testing_nock');

  var couch = nock('nodejsbug.iriscouch.com')
    .put('/testing_nock')
    .reply( 412
     , "{ \"error\":\"file_exists\""+
        ", \"reason\":\"The database could not be created, the file" +
        " already exists.\"}\n"
     , { server: 'CouchDB/1.1.1 (Erlang OTP/R14B04)'
     , date: 'Thu, 01 Dec 2011 17:43:30 GMT'
     , 'content-type': 'application/json'
     , 'content-length': '95'
     , 'cache-control': 'must-revalidate' })
    .post('/testing_nock', "{\"foo\":\"bar\"}")
    .reply(201
     , "{ \"ok\":true" +
       ", \"id\":\"8b787a6a1c2476ef9a2eed069e000ff0\"" +
       ", \"rev\":\"1-4c6114c65e295552ab1019e2b046b10e\"}\n"
     , { server: 'CouchDB/1.1.1 (Erlang OTP/R14B04)'
     , location: 'http://nodejsbug.iriscouch.com/testing_nock/'
       + '8b787a6a1c2476ef9a2eed069e000ff0'
     , date: 'Thu, 01 Dec 2011 17:43:31 GMT'
     , 'content-type': 'application/json'
     , 'content-length': '95'
     , 'cache-control': 'must-revalidate' });

  test('Insert a Document Into CouchDB', function(t) {
    t.plan(4);
    nano.db.create('testing_nock', function () {
      db.insert({foo: "bar"},
        function ensure_insert_worked_cb(err, doc) {
          t.notOk(err, 'No errors');
          t.ok(doc.ok, 'Contains ok');
          t.ok(doc.rev, 'Rev exists');
          t.ok(doc.id, 'Id exists');
        });
    });
  });

 Все работает, счастливого дня! ?

$ node test.js 
  # Insert a Document Into CouchDB
  ok 1 No errors
  ok 2 Contains ok
  ok 3 Rev exists
  ok 4 Id exists

  1..4
  # tests 4
  # pass  4

  # ok

 Источник: http://writings.nunojob.com/2011/12/Mock-Testing-CouchDB-Using-NodeJS-With-Nock-And-TAP.html