【问题标题】:How to mock a function using rewirejs and chai-spies in order to test it?如何使用 rewirejs 和 chai-spie 模拟函数以对其进行测试?
【发布时间】:2017-04-19 14:16:16
【问题描述】:

tl;博士

我正在尝试使用 mochachaichai-spies 测试 express 应用 >重新布线

特别是,我试图做的是模拟模块中存在的函数并使用 chai spy 代替。

我的设置

我有一个名为 db.js 的模块,它导出一个 saveUser() 方法

db.js

module.exports.saveUser = (user) => {
  // saves user to database
};

app.js模块需要db模块

app.js

const db = require('./db');

module.exports.handleSignUp = (email, password) => {
  // create user object
  let user = {
    email: email,
    password: password
  };
  // save user to database
  db.saveUser(user); // <-- I want want to mock this in my test !!
};

最后在我的测试文件app.test.js我有以下内容

app.test.js

const chai = require('chai')
  , spies = require('chai-spies')
  , rewire = require('rewire');

chai.use(spies);
const expect = chai.expect;

// Mock the db.saveUser method within app.js
let app = rewire('./app');
let dbMock = {
  saveUser: chai.spy()
};
app.__set__('db', dbMock);

// Perform the test
it('should call saveUser', () => {
  let email = 'someone@example.com'
    , password = '123456';

  // run the method we want to test
  app.handleSignUp(email, password);

  // assert that the spy is called
  expect(dbMock.saveUser).to.be.spy; // <--- this test passes
  expect(dbMock.saveUser).to.have.been.called(); // <--- this test fails
});

我的问题

我的问题是我确保间谍被 app.handleSignUp 调用的测试失败如下

AssertionError: expected { Spy } to have been called at Context.it (spies/app.test.js:25:40)

我感觉我做错了什么,但我现在卡住了。感谢您的帮助,谢谢

【问题讨论】:

    标签: javascript node.js testing mocking chai


    【解决方案1】:

    最后,我弄清楚了问题所在。来自rewiregithub页面:

    限制

    使用 const 无法重新连接 const(参见 #79)。这个可以 可能有一天会通过代理解决,但需要进一步研究。

    因此,将app.js 中的const db = require('./db'); 更改为let db = require('./db'); 使所有测试通过。

    更好的解决方案

    但是,由于将所有 const 声明更改为 let 以便使用间谍测试应用程序很麻烦,因此以下方法似乎更好:

    我们可以像之前那样将app.js 中的db 模块要求为const,而不是创建spy 并覆盖const 变量:

    let dbMock = {
      saveUser: chai.spy()
    };
    app.__set__('db', dbMock);
    

    我们可以使用rewiregetter方法在我们的app.test.js文件中导入db模块,然后使用我们的spy模拟saveUser()方法(即mutate const 变量的属性之一;由于 JS 中的对象是通过引用传递的,因此在 app.test.js 模块中获取和改变 db 对象也会改变 app.js 中的同一对象模块)

    const db = app.__get__('db');
    db.saveUser = chai.spy()
    

    最后,我们可以预期会调用变异的db.saveUser(即我们的间谍)

    expect(db.saveUser).to.have.been.called();
    

    综上所述,db.jsapp.js 都不会更改,但测试文件现在应该如下所示:

    const chai = require('chai')
      , spies = require('chai-spies')
      , rewire = require('rewire');
    
    chai.use(spies);
    let expect = chai.expect;
    
    // Fetch the app object
    let app = rewire('./app');
    
    // Use the getter to read the const db object and mutate its saveUser property
    const db = app.__get__('db');
    db.saveUser = chai.spy()
    
    // Finally perform the test using the mocked 
    it('should call saveUser', () => {
      let email = 'someone@example.com'
        , password = '123456';
    
      // run the method we want to test
      app.handleSignUp(email, password);
    
      expect(db.saveUser).to.have.been.called(); // <--- now passes!!!
    });
    

    【讨论】:

    • 非常感谢!!!我正在为此而努力。确实,将const 声明更改为let 的解决方案并不理想,但__get__ 解决方案效果惊人!!!
    • 上面的代码对我不起作用,说“TypeError: app.handleSignUp is not a function”
    猜你喜欢
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 2017-02-18
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 2017-03-19
    • 2023-01-26
    相关资源
    最近更新 更多