如何模拟来自 http.request 的响应 (nodejs、jasmine、sinon)

4

我写了一个小的node模块来进行http请求,但是我在测试时遇到了一些问题。
相关代码如下:

module.exports = (function () {
    var http = require("http"),
        Promise = require("promise");

    var send = function send(requestOptions, requestBody) {
        return new Promise(function (resolve, reject) {

            http.request(requestOptions, function (response) {
                var responseChunks = [];

                response.on('data', function (chunk) {
                    responseChunks.push(chunk);
                });

                response.on('end', function () {
                    resolve(Buffer.concat(responseChunks));
                });

                response.on('error', function (e) {
                    reject(e);
                });
            }).end(requestBody);
        });
    };

    return {
        send: send
    }

我正在尝试测试我的send方法,特别是由http.request调用的回调函数。我认为我需要模拟或存根来自http.request的响应对象,以便于我可以测试回调函数的执行。但我想不出如何做到这一点。如果有任何相关的话,我正在使用node v4.1,jasmine v2.3和sinon v1.17。
4个回答

3

除了使用stubbing外,您可以尝试创建一个本地或“mock”服务器来响应请求。这样可以避免 stub out http.request 的情况发生。本地服务器的一个好处是,无论您是使用 http.request、XMLHttpRequest 还是类似的方法来获取在线资源,这种方法都应该有效。

Mock 服务器

您可以尝试 mock 服务器。使用它,您可以创建一个虚拟服务器来满足您的请求。

安装

npm install mockserver-grunt --save-dev
npm install mockserver-client --save-dev

Jasmine 代码

在你的规范(或测试)中,你可以使用以下代码(根据需要进行更改):

var mockServer = require("mockserver-grunt");
var mockServerClient = require("mockserver-client").mockServerClient;

beforeAll(function(done) {
  // start the server
  mockServer.start_mockserver({
    serverPort: 1080,
    verbose: true
  });

  // setup how to respond
  let response = {name:'value'};
  let statusCode = 203;
  mockServerClient("localhost", 1080).mockSimpleResponse('/samplePath', response, statusCode);

  setTimeout(function() {
    // give time for the mock server to setup
    done();
  }, 4000);
});

it("should be able to GET an online resource", function(done) {
   // perform tests, send requests to http://localhost:1080/samplePath
}

这将在1080端口启动服务器。任何请求发送到http://localhost:1080/samplePath都将收到提供的响应。

同样地,服务器可以在测试结束时关闭:

afterAll(function() {
  mockServer.stop_mockserver({
    serverPort: 1080,
    verbose: true
  });
});

其他注意事项

修复损坏的jar文件

当服务器首次启动时,它会尝试下载所需的jar文件。这是一次性下载(据我所知)。如果它没有提供足够的时间,它将无法完全下载,您将得到一个无效或损坏的jar文件。要纠正这个问题,您可以自己下载jar文件。链接在运行中提供。对我来说,它位于https://oss.sonatype.org/content/repositories/releases/org/mock-server/mockserver-netty/3.10.6/mockserver-netty-3.10.6-jar-with-dependencies.jar。很可能,您想导航到最新版本。


更新

Express JS 服务器

自从我最初发布以来,我发现了Express JS。 Express启动服务器实例比Mock Server快得多。您也不必担心jar文件。

安装

npm install express --save-dev

Jasmine Code

var express = require('express');
var app = express();
var port = 3000;
var server;

beforeAll(function() {
  server = app.listen(port, function() {
    console.log("Listening on port " + port);
  });

  app.get('/samplePath', function (req, res) {
    res.send("my response");
  });

});

afterAll(function() {
  // shutdown
  server.close();
});

it("should be able to GET an online resource", function(done) {
   // perform tests, send requests to http://localhost:3000/samplePath
}

如果你想更加高端,可以返回你使用的路径。例如,如果你访问 http://localhost:3000/helloworld,返回值将会是 helloworld。你可以根据需要进行适当的调整。
app.get('/*', function (req, res) {
  res.send(req.params[0]);
});

如果您需要将代码强制进入错误路径,则可以使用

res.status(404)        // HTTP status 404: NotFound
 .send('Not found');

来源:如何使用Express/Node编程发送404响应?


如何配置Express JS的HTTPS

可以使用openssl为Express JS配置HTTPS。通过以下命令创建自签名证书:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

来源:如何使用openssl创建自签名证书?

更新Express JS代码,使用以下方法使用HTTPS。

const secureOptions = {
   key: fs.readFileSync("./spec/ExpressServer/key.pem"),
   cert: fs.readFileSync("./spec/ExpressServer/cert.pem")
};

var secureServer = https.createServer(secureOptions, app);

注意:您可能需要配置应用程序的安全性以允许自签名证书用于HTTPS。

不错的想法,因为它涉及发送真实的http请求。事实上,自从发布原始问题以来,我在许多Java项目中使用mockserver,所以对该项目非常熟悉。不错 :) - Nathan Russell
这是一个很好的想法,但它的实用性可能会受到https加密配置的限制:https://expressjs.com/en/advanced/best-practice-security.html#use-tls - EpicVoyage
太好了!它帮助我向API发送嵌套请求。情况是我正在调用一个API进行集成测试,而该API内部调用另一个API。我需要模拟那个嵌套的API来测试我的API。谢谢。 - Asad Shakeel

2
尝试使用 nock。它非常适合在测试用例中模拟 http 请求。

0

Mocha测试框架和Should.JS(断言库)非常不错。

请参阅入门部分:https://mochajs.org/

基本上,您可以使用mocha框架创建测试用例。然后,您可以使用should.js节点模块进行断言(关于应该发生什么的事实)。

您可以通过npm install mochanpm install should进行安装。

Mocha测试文件代码:

module.exports.run =  function() {
    var chalk = require('chalk');
    var should = require('should');
    var http = require("http");

    describe('test lib description', function(done){
      it('Individual Test Case description', function(done) {
        function send(requestOptions, requestBody) {
            return new Promise(function (resolve, reject) {

                http.request(requestOptions, function (response) {
                    var responseChunks = [];

               // Assertions using Should.JS
               // Example: The http status code from the server should be 200

                    should.equal(response.statusCode , 200);
                    response.should.have.property('someProperty');
                    response.should.have.property('someProperty','someVal');

                    response.on('data', function (chunk) {
                         responseChunks.push(chunk);
                         done(); // Needed To tell mocha we are ready to move on to next test
                    });

                    response.on('end', function () {
                        resolve(Buffer.concat(responseChunks));
                        done();
                    });

                    response.on('error', function (e) {
                        reject(e);
                        done();
                    });
                }).end(requestBody);
            });
       };
     }); 
   });
 }

运行mocha测试:

node ./node_modules/mocha/bin/mocha testFile


在我看来,这似乎是在测试http模块,而OP要求找到一种在不发送http请求的情况下测试处理程序代码的方法。 - EpicVoyage
哇,这是一个旧帖子回来了...我当时正在展示如何对http响应回调对象进行断言。这不仅仅是测试node.JS http模块,而是实际响应参数(即数据)。OP字面上说:“我正在尝试测试我的发送方法”...这是你可以做的一种方式。感谢反馈。 - Peter Hauge

0

我知道这个问题很久以前就被问过了,但万一有人正在寻找不涉及设置附加模拟服务器的快速解决方案,那么可以尝试以下方法。

您可以使用Jasmine的spyOnreturnValue来模拟Node的HTTP包的响应。 Node.js文档 here 读取:

间谍可以替换任何函数并跟踪对它的所有调用和参数。

然后在here中它后来读到:

通过将间谍与and.returnValue链接,所有对该函数的调用都将返回特定值。

所以您需要做的就是:

spyOn(http, "request").and.returnValue(
    //Your mock response goes here.
);

我希望这能帮助其他人。


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