【问题标题】:Can't stub a ReadOnly property twice?不能两次存根 ReadOnly 属性?
【发布时间】:2012-09-24 18:03:47
【问题描述】:

我有以下代码。我有一些合理的理由对该属性进行两次存根(参见下面的解释)。看起来它只让我存根一次。

private IStatus _status;

[SetUp()]
public void Setup() {
  this._status = MockRepository.GenerateStub<IStatus>();
  this._status.Stub(x => x.Connected()).Return(true);
  // This next line would usually be in the Setup for a subclass
  this._status.Stub(x => x.Connected()).Return(false);
}

[Test()]
public void TestTheTestFramework() {
  Assert.IsFalse(this._status.Connected()); // Fails...
}

public interface IStatus {
  bool Connected { get; }
}

我尝试下载最新的build(3.6 build 21),但仍然遇到同样的问题。关于为什么我不能这样做的任何想法?我尝试将IStatus 上的Connected 属性更改为一个函数,但测试仍然失败。我在 VB.Net 中得到相同的行为......错误?

双存根的解释

我正在围绕继承构建我的测试。这样我就可以只做一次通用设置代码,使用注入的模拟依赖项来模拟不同的条件。我可能会提供一个基本/默认存根值(例如,是的,我们已连接),我想在连接断开时测试 SUT 行为的子类中覆盖它。我通常会得到这样的代码。

[TestFixture()]
public class WhenPublishingAMessage {

  // Common setup, inject SUT with mocked dependencies, etc...

  [Test()]
  public void ShouldAlwaysWriteLogMessage {
    //Example of test that would pass for any sub-condition
  }

  [TestFixture()]
  public class AndNoConnection : WhenPublishingAMessage {
    // Do any additional setup, stub dependencies to simulate no connection
    // Run tests for this condition
  }

  [TestFixture()]
  public class AndHaveConnection : WhenPublishingAMessage {
    // Do any additional setup and run tests for this condition
  }
}

编辑

这个post Rhino Mocks 谷歌组可能会有所帮助。看起来我可能需要调用this._status.BackToRecord(); 来重置状态,可以这么说......另外,将.Repeat.Any() 添加到第二个存根语句似乎也有帮助。稍后我将发布更多详细信息。

【问题讨论】:

标签: c# .net nunit rhino-mocks


【解决方案1】:

您可以在第一个结果上指定 .Repeat.Once() 以便它会被使用一次,然后是下一个,如另一个 stack overflow question 中所述

【讨论】:

  • 不幸的是,这不会特别好,因为我希望它在其他子类的测试中多次返回相同的结果,我只想在这个特定的子类中覆盖该行为。
  • 如果您需要不同的行为,您需要将初始化代码移动到适当的测试中,并且可能将每个人都通用的部分留在设置中。您还可以有一个带参数的 setup 方法,并从每个测试中手动调用它,通过您希望在返回第二个结果之前返回第一个结果的次数...
【解决方案2】:

总而言之,可能有三种不同的答案:

Tallmaris 的回答:

使用.Repeat.Times(n).Repeat.Once().Repeat.Twice() 等指定在第一个存根上返回的特定次数。例如:

this._status.Stub(x =&gt; x.Connected()).Return(true).Repeat.Once(); this._status.Stub(x =&gt; x.Connected()).Return(false);

如果我知道在我改变它的行为之前存根将被调用的次数(例如,它只在构造函数中被调用一次),这个方法就会很好地工作。

重置模拟对象

我不喜欢这种方法,因为我想避免(至少对我而言)更麻烦的 Expect/Verify Record/Replay 类型语法。它在response 向我推荐了我在 Rhino Mocks Google 小组中发布的与此问题同名的帖子。

this._status.Stub(x => x.Connected).Return(true);

this._status.GetMockRepository().BackToRecordAll();
this._status.GetMockRepository().ReplayAll();

this._status.Stub(x => x.Connected).Return(false);

使用神奇的Repeat.Any

我发现在第二个存根上使用.Repeat.Any() 会覆盖第一个存根的工作...我感觉有点糟糕添加一些额外的“魔术”代码以使其工作,但在你不知道如何工作的情况下通常告诉第一个存根返回,这个选项会起作用。

this._status.Stub(x => x.Connected()).Return(true);
this._status.Stub(x => x.Connected()).Return(false).Repeat.Any();

注意:你不能多次.Repeat.Any()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 2019-12-11
    • 2020-01-24
    • 2020-11-29
    • 2022-10-16
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多