首页 > 解决方案 > 用 sinon 断言存根方法的参数

问题描述

import ManagerDaoStub from '../salesforce/__test__/ManagerDaoStub';
import criticalMerchants from '../criticalMerchants';
describe('criticalMerchants Unit Tests', () => {
    before(() => {
        ManagerDaoStub.initStubs();    
    });
    after(() => {
        ManagerDaoStub.restoreStubs();
    });
    it('assert the arguments of stubbed method', (done)=>{
        let load = criticalMerchants.createCases(MERCHANT, DEVICE_ID, KEY, {});
        return done();
    });
})

这是在 node 中编写的测试文件criticalMerchants.test.js。我要测试的方法是createCases使用 in 中的方法ManagerDao,该方法已被存根,ManagerDaoStub如下所示。

import ManagerDao from '../ManagerDao';
class ManagerDaoStub {

    constructor() {
       this.sandbox = sinon.sandbox.create();
        }
    initStubs(sandbox) {
        this.sandbox = sandbox || this.sandbox;
        this.restoreStubs();
        this.initFindOpenCases();   
    }
    restoreStubs() {
        this.sandbox.restore();
    }
    initFindOpenCases() {
        let findOpenCases = this.sandbox.stub(ManagerDao, "findOpenCases");
        findOpenCases
            .withArgs(DEVICE_ID, KEY, match.func)
            .callsArgWith(2, new Error("Test error"));
   }
}

我想断言是否initFindOpenCases使用正确的参数(DEVICE_ID、KEY、null)调用了这个存根方法。我用过 sinon.assert.calledWith(ManagerDaoStub.initFindOpenCases, DEVICE_ID, KEY, null),这给出了以下错误:

AssertError: initFindOpenCases() 没有被存根。

有人可以建议一个正确的方法来做到这一点吗?

标签: node.jssinonstubbingsinon-chai

解决方案


首先,如果ManagerDao.initFindOpenCases是一个实例方法(我不确定,因为你没有共享它的定义),那么你不能像你在这里所做的那样在构造函数上存根它:

let findOpenCases = this.sandbox.stub(ManagerDao, "findOpenCases")

您需要先创建一个实例——然后在该实例上存根它——或者像这样在原型本身上存根它:

let findOpenCases = this.sandbox.stub(ManagerDao.prototype, "findOpenCases"); 

其次,你在你的断言中再次犯了同样的错误,再加上另一个:

sinon.assert.calledWith(ManagerDaoStub.initFindOpenCases, DEVICE_ID, KEY, null)

ManagerDaoStub构造函数,它没有initFindOpenCases属性。它的原型确实如此,因此它的实例也是如此。最重要的是,仍然ManagerDaoStub.prototype.initFindOpenCases不是存根。这是您调用以创建存根的方法,但它本身不是存根。更明显的是,您正在与.ManagerDaoManagerDaoStub

假设您在上面进行了示例更改,您可以使您的断言像这样工作:

sinon.assert.calledWith(ManagerDao.prototype.initFindOpenCases, DEVICE_ID, KEY, null)

但是,这并不是我建议更改的全部内容。后一种混淆主要是因为您使测试的设置代码过于复杂。您不需要创建整个类来存根 ManagerDao 的一个方法。

相反,只需将您的beforeafter调用替换为:

beforeEach(() => {
    // Create the stub on the prototype.
    sinon.stub(ManagerDao.prototype, 'findOpenCases')
        .withArgs(DEVICE_ID, KEY, sinon.match.func)
        .callsArgWith(2, newError('Test Error'));
});
afterEach(() => {
    // As of sinon 5.0.0, the sinon object *is* a sandbox, so you can
    // easily restore every fake you've made like so:
    sinon.restore();
});

除此之外,我建议深入研究构造函数的属性与其原型的属性之间的区别。这些知识会让你更容易做这样的事情。最好的起点可能是在 MDN 上


推荐阅读