使用Supertest、Express和Mocha进行Grunt API测试

3

我有一个通过express运行的https服务器,我使用mocha和supertest进行测试。

我的问题是-如果我只运行测试-没问题。如果我尝试运行gruntfile并进行测试,然后再运行express-即使在测试文件中使用了after()与app.close(),我仍会看到许多EADDRINUSE错误。相同的情况也适用于测试任务的监视。

这是我的示例测试:

/* jshint node: true*/
/*global describe, it, after*/
(function() {
    'use strict';
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
    var request = require('supertest');
    var app = require('../server.js').app;
    var expect = require('chai').expect;
    var Cookies;

    after(function(done) {
        app.close();
        setTimeout(function(){done();}, 1500);
    });

    describe('/login', function() {
        it('should auth the user', function(done) {
            request(app)
                .post('/login')
                .send({login: "test", password: 'test'})
                .expect(302)
                .end(function(err, res) {
                    expect(err).to.be.equal(null);
                    expect(res.text).to.be.equal("Moved Temporarily. Redirecting to /");
                    Cookies = res.headers['set-cookie'].pop().split(';')[0];
                    done();
            });

        });
    });
    // testing API for serving session data for angualar factory
    describe('/api/session', function() {
        it('should return session data in JSON', function(done) {
            var req = request(app).get('/api/session');             
                req.cookies = Cookies;
                req.set('Accept','application/json')
                .end(function(err, res) {
                    expect(err).to.be.equal(null);
                    expect(res.body).to.have.property("_id");
                    done();
            });
        });
    });

}());

我知道这些测试距离完美还有很大差距,我刚开始进行适当的软件测试。

所有这些“端口已在使用”都是显而易见的,并且没有一个......会引发任何问题。所有测试都正常工作,服务器也正常工作,但标准输出(stdout)却很疯狂。这种行为远非理想,可能存在许多潜在问题和不稳定性问题。

我的问题是 - 如何摆脱它?

我的想法是:

  • 为测试创建专用服务器,仅使用不同的端口。不幸的是,我不知道如何实现。

  • 对于superagent,如果它没有运行,则制作一些条件来运行服务器,否则将其传递给superagent?

  • 使用其他东西而不是superagent(例如request),但我不确定是否所有cookie和node_tls_reject_unauthorized都会起作用。

正如您所看到的-我在这个主题上挣扎,比答案更多的是问题,并且缺乏足够的经验,不知道该从哪里开始。

我衷心感谢任何帮助。

编辑:

我发现我可以这样做:

before(function(done) {
    app.listen(3001, function() { done(); });
});

该测试在另一个端口启动,但整个server.js仍然被加载,因此它也会启动。然后,当与运行服务器一起触发时,显然会出现EADDRINUSE错误。


看不到你的Gruntfile,但很可能你正在启动Node应用程序,然后进行测试。 - AGDM
1个回答

6
当使用superagent时,您应该始终向其传递已配置的Express应用程序(包括已注册的中间件、路由控制器等)- 但不要将其初始化为HTTP服务器。它会为您执行此操作,并通过http.createServer延迟到操作系统选择一个可用端口。
如果您目前已经有了server.js模块提供的完整HTTP服务器的静态实例,则这很可能是问题的根源。在任何一种情况下,请尝试从实际服务器实例化中提取应用程序配置/引导,如下所示:
// server.js
var express = require('express');
var middleware = require('./middleware');
var controllers = require('./controllers');

// Configures the Express application instance.
exports.setup = function (app) {
    app.use(middleware.foo);
    app.get('/bar', controllers.bar);

    app.locals.baz = 'quux';
}

// You might shoot yourself in the foot if parts of your application depend
// on a static reference at `server.app`.
exports.app = setup(express());
exports.app.listen(3000);

然后,在你的测试中,你可以按照以下方式进行操作:
// tests.js
var express = require('express');
var server = require('./server');

describe('Server tests', function () {
    // Create a fresh server instance prior to each test
    beforeEach(function createNewSever() {
        this.app = server.setup(express());
    });

    describe('Foo', function () {
        it('barrs', function () {
            request(this.app)  // initializes a server instance on port A
            // ... supertests
        });

        it('bazzes', function () {
            request(this.app)  // initializes a server instance on port B
            // ... more supertests
        });
    });
});

这只是为了举例说明,实例化应用程序实例的时间和方式取决于您的测试环境。重要的是,您应该能够为测试用例创建新鲜、干净、独立和隔离的服务器实例。如果您使用一个并行或随机执行测试的测试运行器,这是绝对必要的。


1
服务器.js实际上启动监听端口3000没有问题吗?将设置函数放在单独的模块中是否更好? - Robert Moskal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接