【问题标题】:Mocking a require()'d function using Sinon使用 Sinon 模拟 require() 的函数
【发布时间】:2015-11-10 21:21:06
【问题描述】:

我正在尝试使用Sinon 在测试中模拟request-promise。据我所知,Sinon 模拟对象的方法,而 request-promise 只是返回一个函数。有什么方法可以模拟一个需要的函数吗?

var rp = require('request-promise');
var User = require('../../models/user');

// this works
sinon.stub(User, 'message', function() {});

// This is what I'd like to do to request-promise
sinon.stub(rp, function() {});

我也研究了 mockrequire 和 proxyquire,但我认为它们都遇到了类似的问题。

【问题讨论】:

    标签: javascript node.js unit-testing testing mocking


    【解决方案1】:

    以下示例应该为您解决问题。通过使用 proxyquire,您可以包装 request-promise 并避免存根 .post.get.call 等。在我看来更清洁。

    myModule.js:

    'use strict';
    
    const rp = require('request-promise');
    
    class MyModule {
      /**
       * Sends a post request to localhost:8080 to create a character.
       */
      static createCharacter(data = {}) {
        const options = {
          method: 'POST',
          uri: 'http://localhost:8080/create-character',
          headers: {'content-type': 'application/json'},
          body: data,
        };
        return rp(options);
      }
    }
    
    module.exports = MyModule;
    

    myModule.spec.js:

    'use strict';
    
    const proxyquire = require('proxyquire');
    const sinon = require('sinon');
    const requestPromiseStub = sinon.stub();
    const MyModule = proxyquire('./myModule', {'request-promise': requestPromiseStub});
    
    describe('MyModule', () => {
      it('#createCharacter', (done) => {
        // Set the mocked response we want request-promise to respond with
        const responseMock = {id: 2000, firstName: 'Mickey', lastName: 'Mouse'};
        requestPromiseStub.resolves(responseMock);
        MyModule.createCharacter({firstName: 'Mickey', lastName: 'Mouse'})
          .then((response) => {
            // add your expects / asserts here. obviously this doesn't really
            // prove anything since this is the mocked response.
            expect(response).to.have.property('firstName', 'Mickey');
            expect(response).to.have.property('lastName', 'Mouse');
            expect(response).to.have.property('id').and.is.a('number');
            done();
          })
          .catch(done);
      });
    });
    

    【讨论】:

      【解决方案2】:

      I found a (sort of) solution here.

      基本上,您可以使用 callapply 也可以):

      // models/user.js
      var rp = require('request-promise');
      
      var User = {
          save: function(data) {
              return rp.call(rp, {
                  url: ...,
                  data: data
              });
          }
      }
      module.exports = User;
      
      
      
      // test/user.js
      var rp = require('request-promise');
      var User = require('../../models/user');
      
      describe('User', function() {
          it('should check that save passes data through', function() {
              sinon.stub(rp, 'call', function(data) {
                  // check data here
              });
              User.save({ foo: 'bar' });
          });
      });
      

      它完成了工作,虽然我不喜欢到处都做rp.call,所以我仍然对更好的解决方案抱有希望。

      【讨论】:

      • 更直接的解决方案是存根 rp.get、rp.post 等。这确实需要更改您自己的模块以使用 rp.get({..})/rp.post({..}) 代替 rp({..})。可以说,它也更容易阅读。
      猜你喜欢
      • 2019-10-24
      • 1970-01-01
      • 2013-01-12
      • 2017-07-23
      • 1970-01-01
      • 2017-11-01
      • 2021-09-13
      • 2018-08-28
      • 2020-07-11
      相关资源
      最近更新 更多