Взаимодействие с отслеживанием состояния для тестирования экспресс-приложений

Я написал простой JSON API с экспрессом и пытаюсь использовать мокко для тестирования черного ящика. Тщательное тестирование API требует аутентификации разных пользователей, поэтому каждый тест для конкретной функции состоит как минимум из двух запросов: операции входа в систему и одного или нескольких аутентифицированных запросов, которые проверяют фактическую функцию.

Я не нашел библиотеки, похожей на django.test.client, для имитации взаимодействия с отслеживанием состояния между HTTP-клиентом и сервером. Supertest кажется популярным, но он очень низкоуровневый по сравнению с тестовым клиентом django. Вот как я бы написал с ним простой аутентифицированный тест (извините за мой coffeescript):

it 'should return a 200 OK', (done) ->
  supertest(server.app)
    .post('/login')
    .send("username=xxx&password=pass")
    .end (err, res) ->
      res.should.have.status(200)
      supertest(server.app)
        .get('/api/users')
        .set('cookie', res.headers['set-cookie'][0])
        .expect(200, done)

Действительно ли это самый чистый способ выполнить взаимодействие? Есть ли какая-нибудь библиотека, которая помогла бы мне с асинхронностью (мне не нужно ничего, кроме простой сериализации тестов в 99% случаев, обратные вызовы просто сбивают с толку) и с сохранением состояния? Что-то вроде этого:

it 'should rock', (done) -> myCoolLibrary [
  ->
    @post '/login', {username: "xxx", password: "pass"}, (err, res) =>
      res.should.have.status 200
      @done()
  ,
  ->
    @get '/api/users', (err, res) =>
      res.should.have.status 200
      @done()
  ]

Если ничего похожего не существует, я должен написать это сам :-) Зависимость от контекста связана с тем, что я использую слишком много ZappaJS в эти дни, и благодаря толстой стрелке CoffeeScript это совсем не плохая идиома.


person BruceBerry    schedule 28.04.2013    source источник


Ответы (3)


Похоже, вам могут пригодиться zombiejs. Он имитирует браузер и сохраняет файлы cookie и данные сеанса между запросами.

Он также предоставляет вам более мощные функции, такие как, например, возможность заполнять формы и отправлять их.

Типичный тест будет выглядеть примерно так:

var Browser = require('zombie')
  , browser = new Browser({site:'http://yoursite.com'});
describe('page',function(){
    before(function(done){
        browser.visit('/loginpage',done);
    });
    it('should return a 200 page',function(done){
        browser.fill('username','xxx');
        browser.fill('password','pass');
        //assuming your form points to /login
        browser.pressButton('button[type="submit"]'),function(){
            assert(browser.success); //status code is 2xx
        }).then(done,done); //call the done handler after promise is fulfilled
    });
    it('should rock',function(done){
        browser.visit('/api/users',function(){
            assert(browser.success);
        }).then(done,done);
    });
person gcochard    schedule 29.04.2013

В качестве более общего решения для того, чтобы сделать асинхронный код более понятным для чтения, попробуйте async. https://github.com/caolan/async

async.serial сделает именно то, что вам нужно, но я бы особенно рекомендовал async.auto, который позволяет вам четко связать различные шаги с их зависимостями.

person Dan Kohn    schedule 29.04.2013
comment
В более ранней версии поста было что-то вроде «Это очень похоже на async.series», и это не совпадение. Я должен был оставить это там :-) Очевидно, что в node.js нет никаких строительных блоков, но, исходя из более монолитного фреймворка, я нахожу утомительным открывать и изучать 10 модулей только для того, чтобы сделать что-то настолько простое. В итоге я сам написал очень специфичную для Zappa реализацию, я опубликую ее здесь в какой-то момент. - person BruceBerry; 30.04.2013
comment
Экосистема узлов чем-то похожа на Perl: есть несколько способов сделать это. Вы тратите много времени на оценку возможных вариантов модулей. - person Dan Kohn; 30.04.2013

В итоге я написал себе небольшую библиотеку, которая довольно близка к моему «идеальному» примеру в вопросе. На данный момент он не заслуживает отдельного пакета, поэтому я просто изложил его суть:

https://gist.github.com/BruceBerry/5485917

Я не мог заставить суперагент и супертест выполнять взаимодействие с отслеживанием состояния, поэтому я просто отказался от них в пользу запроса. Основное отличие, по-видимому, заключается в том, что вы не можете связывать ожидания, и вам нужно выполнять все тесты в обратном вызове, но это все равно выглядит странно, если вы уже используете другую библиотеку тестирования, такую ​​как should.js

person BruceBerry    schedule 30.04.2013