【问题标题】:How to mock response from http.request (nodejs, jasmine, sinon)如何模拟来自 http.request 的响应(nodejs,jasmine,sinon)
【发布时间】:2016-01-28 09:18:01
【问题描述】:

我编写了一个小的 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 模拟或存根response 对象,以便我可以测试回调函数的执行。但我不知道该怎么做。

如果有任何相关性,我正在使用 node v4.1、jasmine v2.3 和 sinon v1.17

【问题讨论】:

    标签: node.js http mocking jasmine sinon


    【解决方案1】:

    您可以尝试创建一个本地或“模拟”服务器来响应您的请求,而不是存根。这避免了必须存根 http.request。本地服务器的一个好处是,无论您使用 http.request、XMLHttpRequest 还是类似的方法来获取在线资源,此方法都应该有效。

    模拟服务器

    你可以试试mock server。有了它,您可以创建一个假服务器来满足您的请求。

    安装

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

    茉莉密码

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

    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
    

    茉莉密码

    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');
    

    来源:How to programmatically send a 404 response with Express/Node?


    使用 HTTPS 配置 Express JS

    Express JS 可以配置为使用 HTTPS。使用 openssl,可以使用以下方法创建自签名证书:

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

    来源:How to create a self-signed certificate with 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,因此对该项目非常熟悉。不错:)
    • 这是个好主意,但它的用处可能会受到 https 加密配置的限制:expressjs.com/en/advanced/best-practice-security.html#use-tls
    • 太棒了!它帮助我向 API 发送嵌套请求。案例是我正在调用一个 API 进行集成测试,而该 API 在内部调用了另一个 API。我需要模拟那个嵌套的 API 来测试我的 API。谢谢。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      mocha 测试框架和 Should.JS(断言库)非常好。

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

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

      您可以通过npm install mocha & npm install should 安装它

      摩卡测试文件代码:

      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/mochatestFile

      【讨论】:

      • 在我看来这是在测试 http 模块,而 OP 要求一种方法来测试处理程序代码而不发送 http 请求。
      • 哇,这是一篇老帖子回来了……我展示了如何对 http 响应回调对象进行断言。这不仅仅是测试 node.JS http 模块,而是实际的响应参数(即数据)。 OP字面意思是“我正在尝试测试我的发送方法”......这是您可以做到的一种方法。感谢您的反馈。
      【解决方案4】:

      我知道很久以前就有人问过这个问题,但以防万一有人正在寻找快速解决方案,涉及设置额外的模拟服务器,就在这里。

      您可以使用 Jasmine 的 spyOnreturnValue 来模拟 Node 的 HTTP 包的响应。 Node.js 文档here 内容如下:

      间谍可以存根任何函数并跟踪对其的调用和所有参数。

      然后here 后面写着:

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

      所以你所要做的就是:

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

      我希望这对其他人有所帮助。

      【讨论】:

        猜你喜欢
        • 2022-11-02
        • 2013-05-09
        • 1970-01-01
        • 2022-01-10
        • 2013-08-11
        • 2018-06-15
        • 1970-01-01
        • 2014-10-14
        • 1970-01-01
        相关资源
        最近更新 更多