轻松清理 sinon 存根

Posted

技术标签:

【中文标题】轻松清理 sinon 存根【英文标题】:Cleaning up sinon stubs easily 【发布时间】:2012-07-18 04:11:02 【问题描述】:

有没有一种方法可以轻松地重置所有可以与 mocha 的 beforeEach 块一起干净地工作的 sinon spys 模拟和存根。

我看到沙盒是一种选择,但我不明白如何使用沙盒来实现这一点

beforeEach ->
  sinon.stub some, 'method'
  sinon.stub some, 'mother'

afterEach ->
  # I want to avoid these lines
  some.method.restore()
  some.other.restore()

it 'should call a some method and not other', ->
  some.method()
  assert.called some.method

【问题讨论】:

【参考方案1】:

下面将重置所有存根和嵌套存根。

sinon.reset();

或者你做 NameOfFunctiontionYouWantToReset.resetHistory();

喜欢 addingStub.resetHistory();

【讨论】:

【参考方案2】:

创建一个沙盒,它将充当所有间谍、存根、模拟和伪造品的黑盒容器。

您所要做的就是在第一个描述块中创建一个沙箱,以便在所有测试用例中都可以访问它。一旦你完成了所有的测试用例,你应该释放原始方法并使用 afterEach 钩子中的方法sandbox.restore() 清理存根,以便在运行时它释放持有的资源afterEach 测试用例通过或失败。

这是一个例子:

 describe('MyController', () => 
    //Creates a new sandbox object
    const sandbox = sinon.createSandbox();
    let myControllerInstance: MyController;

    let loginStub: sinon.SinonStub;
    beforeEach(async () => 
        let config = key: 'value';
        myControllerInstance = new MyController(config);
        loginStub = sandbox.stub(ThirdPartyModule, 'login').resolves(success: true);
    );
    describe('MyControllerMethod1', () => 
        it('should run successfully', async () => 
            loginStub.withArgs(username: 'Test', password: 'Test').resolves();
            let ret = await myControllerInstance.run();
            expect(ret.status).to.eq('200');
            expect(loginStub.called).to.be.true;
        );
    );
    afterEach(async () => 
        //clean and release the original methods afterEach test case at runtime
        sandbox.restore(); 
    );
);

【讨论】:

【参考方案3】:

以前的答案建议使用sandboxes 来完成此操作,但根据the documentation:

从 sinon@5.0.0 开始,sinon 对象是默认的沙箱。

这意味着清理你的存根/模拟/间谍现在很容易:

var sinon = require('sinon');

it('should do my bidding', function() 
    sinon.stub(some, 'method');


afterEach(function () 
    sinon.restore();
);

【讨论】:

这是 2018 年 4 月之后阅读本文的任何人的最佳答案。 甚至更奇怪:afterEach(sinon.restore) 我认为这更好,因为显式沙箱会产生不必要的复杂性。你真的需要几个独立的沙箱,对同一个对象有不同的模拟吗?可能不会。 是不是说sinon.stub(some, 'method'); 没有区别和 const sandbox = sinon.createSandbox(); sandbox.stub(some, 'method'); ? 当我在 afterEach 钩子中使用 sinon.restore() 时收到此消息 (sinon.restore is deprecated and will be removed from the public API in a future version of sinon.)【参考方案4】:

Sinon 通过使用Sandboxes 来提供此功能,可以通过以下几种方式使用:

// manually create and restore the sandbox
var sandbox;
beforeEach(function () 
    sandbox = sinon.sandbox.create();
);

afterEach(function () 
    sandbox.restore();
);

it('should restore all mocks stubs and spies between tests', function() 
    sandbox.stub(some, 'method'); // note the use of "sandbox"

// wrap your test function in sinon.test()
it("should automatically restore all mocks stubs and spies", sinon.test(function() 
    this.stub(some, 'method'); // note the use of "this"
));

【讨论】:

@CamJackson 当你有异步测试时,你需要使用第一种方法,否则 sinon 在你的测试执行完成之前清理它的存根。 如果您使用的是 sinon >5.0,请阅读下文。现在有一个更简单的方法:***.com/a/55251560/4464702【参考方案5】:

@keithjgrant 答案的更新。

v2.0.0 版本开始,sinon.test 方法已移至a separate sinon-test module。要使旧测试通过,您需要在每个测试中配置这个额外的依赖项:

var sinonTest = require('sinon-test');
sinon.test = sinonTest.configureTest(sinon);

或者,您可以不使用 sinon-test 并使用 sandboxes:

var sandbox = sinon.sandbox.create();

afterEach(function () 
    sandbox.restore();
);

it('should restore all mocks stubs and spies between tests', function() 
    sandbox.stub(some, 'method'); // note the use of "sandbox"
 

【讨论】:

或者你可以实际使用 sinon-test 包并像以前一样继续你的代码:-D【参考方案6】:

如果您想要一个让 sinon 始终为所有测试自行重置的设置:

在 helper.js 中:

import sinon from 'sinon'

var sandbox;

beforeEach(function() 
    this.sinon = sandbox = sinon.sandbox.create();
);

afterEach(function() 
    sandbox.restore();
);

那么,在你的测试中:

it("some test", function() 
    this.sinon.stub(obj, 'hi').returns(null)
)

【讨论】:

【参考方案7】:

restore() 只是恢复存根功能的行为,但不会重置存根的状态。您必须使用 sinon.test 包装您的测试并使用 this.stub 或在存根上单独调用 reset()

【讨论】:

【参考方案8】:

请注意,当使用 qunit 代替 mocha 时,您需要将它们包装在一个模块中,例如

module("module name"

    //For QUnit2 use
    beforeEach: function() 
    //For QUnit1 use
    setup: function () 
      fakes = sinon.collection;
    ,

    //For QUnit2 use
    afterEach: function() 
    //For QUnit1 use
    teardown: function () 
      fakes.restore();
    
);

test("should restore all mocks stubs and spies between tests", function() 
      stub = fakes.stub(window, 'someFunction');
    
);

【讨论】:

qunit 2 正在切换到beforeEachafterEachsetupteardown 方法将被弃用。【参考方案9】:

您可以使用 sinon 库作者在 this 博客文章(日期为 2010 年 5 月)中说明的 sinon.collection。

sinon.collection api 发生了变化,使用方法如下:

beforeEach(function () 
  fakes = sinon.collection;
);

afterEach(function () 
  fakes.restore();
);

it('should restore all mocks stubs and spies between tests', function() 
  stub = fakes.stub(window, 'someFunction');

【讨论】:

以上是关于轻松清理 sinon 存根的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sinon 存根 new Date()?

使用 Sinon 存根 window.location.href

用 sinon 存根,用 chai 测试

如何使用 Sinon 存根 npm 包 `phin`

Sinon中JSON模块的存根独立函数

使用 sinon 为 redux 操作存根闭包函数