如何使用rewirejs和chai-spies来模拟一个函数来testing它?

TL;博士

我正在尝试使用摩卡chaichai-spiesrewire来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); 

我们可以使用rewiregetter方法在我们的app.test.js文件中导入db模块,然后使用我们的spy模拟saveUser()方法(即改变其中一个constvariables的属性;因为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都不会被改变,但是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!!! });