2012-01-12 132 views
64

我刚刚添加了shouldjs和mocha到我的快速应用程序进行测试,但我想知道如何测试我的应用程序。我愿做这样的:我如何测试我的快速应用程序与摩卡?

当然,在测试套件的最后一个测试只是告诉配有该res.render功能(称为show_create_user_screen内)是不确定的,可能becouse服务器不在运行和配置尚未完成。所以我想知道其他人是如何进行测试的?

+0

就像上面添加的示例是因为它简短而简短。通常我会测试在调用某个路由器函数之后,给定的req/res对象上的适当函数或值被设置/调用。以下答案足够。人们不应该测试路由器的功能,这是网络框架的工作。 – 2012-06-26 10:37:46

回答

32

OK,首先虽然测试你的路由代码的东西,你可能会或可能不会想要做的,在一般情况下,尝试将有趣的商业逻辑在纯JavaScript代码(类或函数)是由快递脱钩分离或者你正在使用的任何框架,并使用香草摩卡测试来测试。如果你想真正测试你在摩卡配置的路由,一旦你达到了这个目标,你需要传递req, res模拟参数到你的中间件功能来模拟express/connect和你的中间件之间的接口。

对于一个简单的情况,你可以用render函数创建一个模拟res对象,看起来像这样。

describe 'routes', -> 
    describe '#show_create_user_screen', -> 
    it 'should be a function', -> 
     routes.show_create_user_screen.should.be.a.function 
    it 'should return something cool', -> 
     mockReq = null 
     mockRes = 
     render: (viewName) -> 
      viewName.should.exist 
      viewName.should.match /createuser/ 

     routes.show_create_user_screen(mockReq, mockRes).should.be.an.object 

也只是FYI中间件功能不需要返回任何特定的值,这是他们做什么与req, res, next参数,你应该专注于测试。

以下是您在评论中请求的一些JavaScript。

describe('routes', function() { 
    describe('#show_create_user_screen', function() { 
     it('should be a function', function() { 
     routes.show_create_user_screen.should.be.a["function"]; 
     }); 
     it('should return something cool', function() { 
     var mockReq = null; 
     var mockRes = { 
      render: function(viewName) { 
      viewName.should.exist; 
      viewName.should.match(/createuser/); 
      } 
     }; 
     routes.show_create_user_screen(mockReq, mockRes); 
     }); 
    }); 
    }); 
+1

嘲讽并没有给你的一件事是防止你正在使用的模块的API变化。例如如果明确更新并更改渲染的名称,则不受保护。理想情况下,你也在测试,但有时集成+单元测试可以一次测试很多代码,这取决于你如何看待它,这是好事还是坏事。编辑:虽然我非常喜欢这种模拟方法,但它确实很轻巧。 – timoxley 2012-04-02 12:23:28

+61

请不要总是添加编译后的js,有些人对阅读coffeescript不熟悉。 – 2012-10-21 11:45:18

+0

这不是测试的实现细节吗?您实际上想要测试返回时的'响应'对象包含的内容 - 如果将来您不使用'render'方法来执行此操作,例如在重构期间,您的测试将失败并且不会向您显示重构的代码工作,因为你将不得不重写测试? 只是一个念头!否则,它是嘲笑响应对象的一种巧妙方式。 – SimonB 2014-07-04 14:19:57

6

摩卡自带之前,之前,之后,以及之后的每一个bdd测试。在这种情况下,您应该在您的描述调用之前使用。

describe 'routes' -> 
    before (done) -> 
    app.listen(3000) 
    app.on('connection', done) 
5

我发现最简单的方法来设置要作为帮手,以及一个 帮手HTTP客户端TESTSERVER类,只是做一个真正的http服务器真正的请求。但是,有些情况下你想要模拟和存储这些东西。

// Test file 
var http = require('the/below/code'); 

describe('my_controller', function() { 
    var server; 

    before(function() { 
     var router = require('path/to/some/router'); 
     server = http.server.create(router); 
     server.start(); 
    }); 

    after(function() { 
     server.stop(); 
    }); 

    describe("GET /foo", function() { 
     it('returns something', function(done) { 
      http.client.get('/foo', function(err, res) { 
       // assertions 
       done(); 
      }); 
     }); 
    }); 
}); 


// Test helper file 
var express = require('express'); 
var http  = require('http'); 

// These could be args passed into TestServer, or settings from somewhere. 
var TEST_HOST = 'localhost'; 
var TEST_PORT = 9876; 

function TestServer(args) { 
    var self = this; 
    var express = require('express'); 
    self.router = args.router; 
    self.server = express.createServer(); 
    self.server.use(express.bodyParser()); 
    self.server.use(self.router); 
} 

TestServer.prototype.start = function() { 
    var self = this; 
    if (self.server) { 
     self.server.listen(TEST_PORT, TEST_HOST); 
    } else { 
     throw new Error('Server not found'); 
    } 
}; 

TestServer.prototype.stop = function() { 
    var self = this; 
    self.server.close(); 
}; 

// you would likely want this in another file, and include similar 
// functions for post, put, delete, etc. 
function http_get(host, port, url, cb) { 
    var options = { 
     host: host, 
     port: port, 
     path: url, 
     method: 'GET' 
    }; 
    var ret = false; 
    var req = http.request(options, function(res) { 
     var buffer = ''; 
     res.on('data', function(data) { 
      buffer += data; 
     }); 
     res.on('end',function(){ 
      cb(null,buffer); 
     }); 
    }); 
    req.end(); 
    req.on('error', function(e) { 
     if (!ret) { 
      cb(e, null); 
     } 
    }); 
} 

var client = { 
    get: function(url, cb) { 
     http_get(TEST_HOST, TEST_PORT, url, cb); 
    } 
}; 

var http = { 
    server: { 
     create: function(router) { 
      return new TestServer({router: router}); 
     } 
    }, 

    client: client 
}; 
module.exports = http; 
+0

刚刚意识到我错过了你的问题的重点,但也许这将有助于反正。我个人不会自己测试路由器的功能。我只是通过HTTP请求来测试服务器基本上做了什么,然后单独测试所有的业务逻辑,因为它全部都在控制器之外的文件中。 – 2012-01-17 02:44:42

+0

你已经有了对'path/to/some/router'的引用,并且看到该文件的内容会很有帮助。 – 2012-03-26 05:31:04

64
发现

connect.js tests suites

替代它们使用supertest测试一个连接的应用程序而不结合服务器向任何端口并且不使用模拟式窗口。

这里是连接的静态中间件测试套件的摘录(使用摩卡作为测试运行和supertest的断言)

var connect = require('connect'); 

var app = connect(); 
app.use(connect.static(staticDirPath)); 

describe('connect.static()', function(){ 
    it('should serve static files', function(done){ 
    app.request() 
    .get('/todo.txt') 
    .expect('contents', done); 
    }) 
}); 

这适用于快递应用程序,以及

+0

我只能接受一个答案,否则这也会被接受=) – 2012-07-17 09:54:53

+1

app.request在我的最新express/connect中不起作用,所以我更新了这个答案以匹配https://的用法github.com/visionmedia/supertest – Aaron 2013-01-23 06:32:35

+0

关于'supertest'的条款看起来有误导性。似乎没有在[连接代码]中提到它(https://github.com/search?q=supertest+repo%3A%22senchalabs%2Fconnect%22&type=Code&ref=searchresults)。 反正Alexandru的回答看起来比其他人好。 – yanychar 2014-01-31 21:38:21

21

你可以尝试SuperTest,和那么服务器启动和关闭将被处理:

var request = require('supertest') 
    , app  = require('./anExpressServer').app 
    , assert = require("assert"); 

describe('POST /', function(){ 
    it('should fail bad img_uri', function(done){ 
    request(app) 
     .post('/') 
     .send({ 
      'img_uri' : 'foobar' 
     }) 
     .expect(500) 
     .end(function(err, res){ 
      done(); 
     }) 
    }) 
}); 
+0

SuperTest为我工作至少一打项目。为了胜利! – deepelement 2014-10-20 12:25:57

+1

我不知道'supertest'和'chaihttp'有什么区别? – toszter 2017-08-24 00:07:51