如何使用 rewirejs 和 chai-spies 模拟函数以测试它?
How to mock a function using rewirejs and chai-spies in order to test it?
tl;博士
我正在尝试使用 mocha、chai、chai-spies 和 rewire。
特别是,我想做的是模拟模块中存在的函数并改用 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)
我觉得我做错了什么,但我现在卡住了。感谢任何帮助,谢谢
终于明白问题出在哪里了。来自 rewire github 页:
Limitations
Using const It's not possible to rewire const (see #79). This can
probably be solved with proxies someday but requires further research.
因此,在 app.js
中将 const db = require('./db');
更改为 let db = require('./db');
使所有测试都通过了。
更好的解决方案
但是,由于将所有 const
声明更改为 let
以测试带有间谍的应用程序很麻烦,因此以下方法似乎更好:
我们可以像以前那样在 app.js
中将我们的 db
模块作为 const
,而不是创建间谍并覆盖 const 变量:
let dbMock = {
saveUser: chai.spy()
};
app.__set__('db', dbMock);
我们可以使用rewire
的getter方法在我们的app.test.js
文件中导入db
模块,并且然后使用我们的间谍模拟 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.js
和 app.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!!!
});
tl;博士
我正在尝试使用 mocha、chai、chai-spies 和 rewire。
特别是,我想做的是模拟模块中存在的函数并改用 chai spy。
我的设置
我有一个名为 db.js
的模块,它导出一个 saveUser()
方法
db.js
module.exports.saveUser = (user) => {
// saves user to database
};
app.js
模块
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)
我觉得我做错了什么,但我现在卡住了。感谢任何帮助,谢谢
终于明白问题出在哪里了。来自 rewire github 页:
Limitations
Using const It's not possible to rewire const (see #79). This can probably be solved with proxies someday but requires further research.
因此,在 app.js
中将 const db = require('./db');
更改为 let db = require('./db');
使所有测试都通过了。
更好的解决方案
但是,由于将所有 const
声明更改为 let
以测试带有间谍的应用程序很麻烦,因此以下方法似乎更好:
我们可以像以前那样在 app.js
中将我们的 db
模块作为 const
,而不是创建间谍并覆盖 const 变量:
let dbMock = {
saveUser: chai.spy()
};
app.__set__('db', dbMock);
我们可以使用rewire
的getter方法在我们的app.test.js
文件中导入db
模块,并且然后使用我们的间谍模拟 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.js
和 app.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!!!
});