如何使用rewirejs和chai-spies来模拟一个函数来testing它?
TL;博士
我正在尝试使用摩卡 , chai , chai-spies和rewire来testing一个快速应用程序 。
特别是,我试图做的是模拟一个模块中存在的函数,而不是使用chai间谍。
我的设置
我有一个名为db.js
的模块,它导出一个saveUser()
方法
db.js
module.exports.saveUser = (user) => { // saves user to database };
db模块是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 !! };
最后在我的testing文件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 });
我的问题
我的问题是,我的testing确保间谍被app.handleSignUp调用失败,如下所示
AssertionError: expected { Spy } to have been called at Context.it (spies/app.test.js:25:40)
我觉得我做错了什么,但是我现在被卡住了。 任何帮助表示赞赏,谢谢
最后,我找出了问题所在。 来自rewire github页面:
限制
使用const不可能重新连接const(参见#79)。 这可能有可能用代理解决,但需要进一步的研究。
所以,改变const db = require('./db');
let db = require('./db');
在app.js
所有的testing通过。
更好的解决scheme
然而,因为改变所有的const
声明let
为了用间谍testing一个应用程序是一件麻烦的事情,下面的方法似乎更好一些:
我们可以在app.js
中将我们的db
模块作为const
来使用,而不是创buildspy并覆盖constvariables:
let dbMock = { saveUser: chai.spy() }; app.__set__('db', dbMock);
我们可以使用rewire
的getter方法在我们的app.test.js
文件中导入db
模块,然后使用我们的spy模拟saveUser()
方法(即改变其中一个const
variables的属性;因为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
都不会被改变,但是testing文件应该如下所示:
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!!! });