Node.js:模拟 HTTP 请求和响应

41

有没有方便的方法来为单元测试中间件模拟HTTP请求和响应对象?


你为什么在测试用例中不包含真实的HTTP请求呢?在异步测试环境中应该是可行的。 - b_erb
11
我同意这个选择,但说实话它感觉不像单元测试,更像集成测试。无论如何,目前这是我最好的选择。 - 7elephant
8
我不想包含真正的HTTP请求,因为这会使我的测试变慢且不够可靠。例如,如果我调用的某个服务是基于DB的,并且因为QA中的DB已被清除(或与生产环境同步等原因)而失败,则我的测试就会失败。另外,如果你不进行模拟,那么要可靠地强制发生某些错误情况几乎是不可能的。不,我喜欢模拟--它们使测试更容易、更可靠。 - Kevin
9个回答

27

1
node-mocks-http 看起来是原始帖子的一个很好的解决方案。 - newz2000
好的,刚刚发现node-mocks-http真是太棒了。(可以在不实际进行http请求的情况下测试请求处理程序) - Dmitri Zagidulin

11

从标签上看,这个问题似乎是关于 Express 的。如果是这样的话,supertest 是非常好用的:

var request = require('supertest')
  , express = require('express');

var app = express();

app.get('/user', function(req, res){
  res.send(201, { name: 'tobi' });
});

request(app)
  .get('/user')
  .expect('Content-Type', /json/)
  .expect('Content-Length', '20')
  .expect(201)
  .end(function(err, res){
    if (err) throw err;
  });

对于一般的Node使用,Flatiron Nock似乎是一个不错的选择:

var nock = require('nock');
var example = nock('http://example.com')
                .get('/foo')
                .reply(200, { foo: 'bar' });

var http = require('http');
var options = {
  host: 'example.com',
  port: 80,
  path: '/foo',
  method: 'GET'
}
var req = http.request(options, function(res) {
  res.on('data', function(chunk) {
    console.log('BODY: ' + chunk);
  });
});

req.on('error', function(e) {
  console.log('error: ' + e);
});

req.end();

输出:

正文:{"foo":"bar"}


1
这是一篇旧帖子。但我有一个问题。supertest,它有 request(app),似乎启动了一个服务器(https://github.com/tj/supertest/blob/master/index.js#L20),并且它没有模拟 HTTP 请求。这是真的吗? - NullSpace

2
如果您只想对处理程序进行单元测试,可以将 express.Requestexpress.Response 对象注入到请求函数中,或者在这种情况下,注入到您的中间件中。其中一个看起来提供了最少的方法,同时保持简单,对我来说是 @jest-mock/express
如果您正在使用 supertestnock,则正在进行集成测试,这可能会耦合多个测试。我还会研究一下它的内部工作方式,因为一旦停止工作,调试将会很麻烦。
it('should call next',
        async () => {
            const req = getMockReq({
              headers: {
                'user-agent': 'Chrome',
              },
              path: '/path',
            })
            const{res, next, clearMockRes} = getMockRes({})
            await middleware(req, res, next)

            expect(res.send).not.toHaveBeenCalledWith()
            expect(next).toHaveBeenCalled()
        })

2

4
该项目已经被弃用。建议使用 "nock" https://github.com/flatiron/nock。 - Guido

2

1

Mockery 在这方面非常棒。

它基本上劫持了 require 调用,并返回您指定的不同对象/函数存根。


1

0

我不建议在实际使用中使用这个解决方案,但这是我在实验中避免异常的hack方法。

const mock_response_obj = {
    statusCode: null,
    setHeader: () => {},
    writeHead: () => {},
    end: () => {},
}

显然需要根据需要进行扩展。分享给其他人,以防有人正在寻找简单的临时解决方案。


-1

我鼓励您使用motty。为什么我们需要另一个代码呢?


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