【问题标题】:How to mock only one method using Sinon?如何使用 Sinon 仅模拟一种方法?
【发布时间】:2014-09-15 10:31:13
【问题描述】:

我的命名空间中有一个方法我想mock,但我希望所有其他方法都能正常工作。是否可以让 sinon 模拟一个特定的方法,同时让其他方法保持不变?

我的理解是我不是在寻找间谍,因为我想断言模拟是使用特定参数调用的。

这是我在 CoffeeScript 中的代码:

root.targeting.handleUnitsAttack = (gameState) ->
  units = gameState.heroes.concat(gameState.badGuys)
  for source in units
    for target in units
      gameState = root.targeting.sourceAttackTarget(gameState, source, target)
  gameState

我想模拟 sourceAttackTarget 并验证它的参数是特定值。

【问题讨论】:

    标签: javascript coffeescript qunit sinon


    【解决方案1】:

    是的,这是 sinon@2 最常见的用例之一,但我相信您要寻找的既不是模拟也不是间谍,而是存根。

    见:https://sinonjs.org/releases/v2.4.1/stubs/

    var stub = sinon.stub(object, "foo");
    //do your assertions
    stub.restore(); //back to normal now.
    

    这将允许您创建一个替换 object.foo() 的默认函数。

    但是,从您的问题来看,听起来 no-op 存根函数不是您所追求的,而是想用您自己的自定义函数覆盖它:

    var stub = sinon.stub(object, "foo", function customFoo() { /* ... */ });
    //do your assertions
    stub.restore(); //back to normal now.
    

    HTH!


    编辑:

    如何存根单个函数:

    以下存根object.sourceAttackTarget()

    var stub = sinon.stub(object, "sourceAttackTarget", function sourceAttackTargetCustom(gameState, source, target) {
        //do assertions on gameState, source, and target
        // ...
        return customReturn;
    });
    //do any further assertions
    stub.restore(); //back to normal now.
    

    如何存根函数以测试特定参数

    var stub = sinon.stub(object, "sourceAttackTarget");
    stub.withArgs(1, "foo", "bar").returns("correctTarget");
    stub.returns("wrongTarget");
    var output = object.sourceAttackTarget(gameState, source, target);
    equal(output, "correctTarget", 'sourceAttackTarget invoked with the right arguments');
    //do any further assertions
    stub.restore(); //back to normal now.
    

    (更新)

    还有.calledWith().calledWithMatch(),这是我刚刚发现的。也可以证明对这类测试非常有用。

    如何只模拟一个对象的一种方法:

    “Mocks 带有可能无法通过测试的内置期望。因此,它们强制执行实现细节。经验法则是:如果您不为某些特定调用添加断言,请不要模拟它。使用取而代之的是一个存根。一般来说,在一个测试中你永远不应该有超过一个模拟(可能有几个期望)。 - source

    ...所以对于上面提出的问题,模拟是正确的选择,而存根是合适的选择。话虽如此,其中一个场景可以使用模拟轻松测试,即期望使用一组特定的参数调用方法。

    var mock = sinon.mock(object);
    mock.expects("sourceAttackTarget").withArgs(1, "foo", "bar");
    object.sourceAttackTarget(gameState, source, target);
    mock.verify();
    

    【讨论】:

    • 我实际上想在最后验证一下。我想验证是否使用特定参数调用了模拟。
    • 事实上,我实际上也想控制模拟方法返回的内容。我觉得我想要一切可能,尽管我的代码很简单。我将编辑我的问题以显示它。
    • 如果您想验证该方法是使用特定参数调用的,那么一个简单的存根就足够了。否则,请使用第二个选项,在其中添加自定义函数,在自定义函数中对预期参数进行断言,然后返回所需的值。
    • 是的,object 是包含您希望存根的函数的变量。在这种情况下,这将是root.targeting。 sinon 在幕后所做的是var methodBeforeStubbing = object[methodName];
    • 答案已经过时了。 sinon stub的正确使用方式变成了stub(obj, 'meth').callsFake(fn)
    【解决方案2】:

    从 sinon@3.0.0 开始,

    var stub = sinon.stub(object, "method", func);
    

    已被删除。更应该使用:

    stub(object, "method").callsFake(func)
    
    stub.callsFake(fakeFunction);
    Makes the stub call the provided fakeFunction when invoked.
    
    var myObj = {};
    myObj.prop = function propFn() {
        return 'foo';
    };
    
    sinon.stub(myObj, 'prop').callsFake(function fakeFn() {
        return 'bar';
    });
    
    myObj.prop(); // 'bar'
    

    来源:sinonjs docs

    【讨论】:

      猜你喜欢
      • 2020-05-13
      • 2022-01-04
      • 2015-04-09
      • 1970-01-01
      • 2018-05-26
      • 2021-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多