如何重置存根中属性的结果而不重置整个存根?

发布于 2024-08-09 22:35:52 字数 2617 浏览 1 评论 0原文

我是 Rhino Mocks 的新手,所以我可能完全错过了一些东西。

假设我有一个具有六个属性的接口:

public interface IFoo {
  string Foo1 { get; } // Required non-null or empty
  string Foo2 { get; } // Required non-null or empty
  string Foo3 { get; }
  string Foo4 { get; }
  int Foo5 { get; }
  int Foo6 { get; }
}

以及一个采用类似对象但没有相同约束并创建 IFoo 实例的实现:

public interface IFooLikeObject {
  string FooLikeObject1 { get; } // Okay non-null or empty
  string FooLikeObject2 { get; } // Okay non-null or empty
  string FooLikeObject3 { get; }
  string FooLikeObject4 { get; }
  string FooLikeObject5 { get; } // String here instead of int
  string FooLikeObject6 { get; } // String here instead of int
}

public class Foo : IFoo {
  public Foo(IFooLikeObject fooLikeObject) {

    if (string.IsNullOrEmpty(fooLikeObject.Foo1)) {
      throw new ArgumentException("fooLikeObject.Foo1 is a required element and must not be null.")
    }

    if (string.IsNullOrEmpty(Foo2)) {
      throw new ArgumentException("fooLikeObject.Foo2 is a required element and must not be null")
    }

    // Make all the assignments, including conversions from string to int...

  }
}

现在在我的测试中,我想测试在适当的时间抛出异常以及从 string 到 int 的失败转换期间引发的异常。

因此,我需要太存根 IFooLikeObject 来返回我当前未测试的值的有效值,并且由于我不想在每个测试方法中重复此代码,因此我将其提取到单独的方法中。

public IFooLikeObject CreateBasicIFooLikeObjectStub(MockRepository mocks) {
  IFooLikeObject stub = mocks.Stub<IFooLikeObject>();

  // These values are required to be non-null
  SetupResult.For(stub.FooLikeObject1).Return("AValidString");
  SetupResult.For(stub.FooLikeObject2).Return("AValidString2");
  SetupResult.For(stub.FooLikeObject5).Return("1");
  SetupResult.For(stub.FooLikeObject6).Return("1");
}

这对于测试 Foo3 和 Foo4 来说效果很好,但是当测试 Foo1、2、5 或 6 时,我得到:

System.InvalidOperationException : The result for IFooLikeObject.get_FooLikeObject1(); has already been setup. Properties are already stubbed with PropertyBehavior by default, no action is required

例如:

[Test]
void Constructor_FooLikeObject1IsNull_Exception() {
  MocksRepository mocks = new MocksRepository();
  IFooLikeObject fooLikeObjectStub = CreateBasicIFooLikeObjectStub(mocks);

// This line causes the exception since FooLikeObject1 has already been set in CreateBasicIFooLikeObjectStub()
  SetupResult.For(fooLikeObjectStub.FooLikeObject1).Return(null); 

  mocks.ReplayAll();

  Assert.Throws<ArgumentException>(delegate { new Foo(fooLikeObjectStub); });
}

我如何设置它,以便我可以覆盖已经设置了返回值的单个属性,而无需还必须重做所有其他的吗?

I'm new to Rhino Mocks, so I may be missing something completely.

Lets say I have an interface with has a half dozen properties:

public interface IFoo {
  string Foo1 { get; } // Required non-null or empty
  string Foo2 { get; } // Required non-null or empty
  string Foo3 { get; }
  string Foo4 { get; }
  int Foo5 { get; }
  int Foo6 { get; }
}

And an implementation which takes a similar object but without the same constraints and creates an IFoo instance:

public interface IFooLikeObject {
  string FooLikeObject1 { get; } // Okay non-null or empty
  string FooLikeObject2 { get; } // Okay non-null or empty
  string FooLikeObject3 { get; }
  string FooLikeObject4 { get; }
  string FooLikeObject5 { get; } // String here instead of int
  string FooLikeObject6 { get; } // String here instead of int
}

public class Foo : IFoo {
  public Foo(IFooLikeObject fooLikeObject) {

    if (string.IsNullOrEmpty(fooLikeObject.Foo1)) {
      throw new ArgumentException("fooLikeObject.Foo1 is a required element and must not be null.")
    }

    if (string.IsNullOrEmpty(Foo2)) {
      throw new ArgumentException("fooLikeObject.Foo2 is a required element and must not be null")
    }

    // Make all the assignments, including conversions from string to int...

  }
}

Now in my tests I want to test both that the exceptions are thrown at the proper times and also the exceptions thrown during failed conversions from string to int.

So I need too stub out IFooLikeObject to return valid values for the values I'm not currently testing, and since I don't want to duplicate this code in every test method I extract it out into a seperate method.

public IFooLikeObject CreateBasicIFooLikeObjectStub(MockRepository mocks) {
  IFooLikeObject stub = mocks.Stub<IFooLikeObject>();

  // These values are required to be non-null
  SetupResult.For(stub.FooLikeObject1).Return("AValidString");
  SetupResult.For(stub.FooLikeObject2).Return("AValidString2");
  SetupResult.For(stub.FooLikeObject5).Return("1");
  SetupResult.For(stub.FooLikeObject6).Return("1");
}

This works well enough for testing Foo3 and Foo4, but when testing Foo1, 2, 5, or 6 I get:

System.InvalidOperationException : The result for IFooLikeObject.get_FooLikeObject1(); has already been setup. Properties are already stubbed with PropertyBehavior by default, no action is required

For example:

[Test]
void Constructor_FooLikeObject1IsNull_Exception() {
  MocksRepository mocks = new MocksRepository();
  IFooLikeObject fooLikeObjectStub = CreateBasicIFooLikeObjectStub(mocks);

// This line causes the exception since FooLikeObject1 has already been set in CreateBasicIFooLikeObjectStub()
  SetupResult.For(fooLikeObjectStub.FooLikeObject1).Return(null); 

  mocks.ReplayAll();

  Assert.Throws<ArgumentException>(delegate { new Foo(fooLikeObjectStub); });
}

How can I set it up so that I can override an individual property which already has a return value set up without having to redo all the others as well?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别闹i 2024-08-16 22:35:52

这可以使用 Repeat.Any() 构造来完成。

我尚未使用 SetupResult.For 语法对此进行测试,但它适用于 lambda 语法:

public IFooLikeObject CreateBasicIFooLikeObjectStub(MockRepository) {
  IFooLikeObject stub = MockRepository.GenerateStub<IFooLikeObject>();

  // These values are required to be non-null
  stub.Stub(s => s.FooLikeObject1).Return("AValidString");
  stub.Stub(s => s.FooLikeObject2).Return("AValidString2");
  stub.Stub(s => s.FooLikeObject5).Return("1");
  stub.Stub(s => s.FooLikeObject6).Return("1");
}

[Test]
void Constructor_FooLikeObject1IsNull_Exception() {
  IFooLikeObject fooLikeObjectStub = CreateBasicIFooLikeObjectStub();

  // This line no longer causes an exception
  stub.Stub(s => s.FooLikeObject1).Return(null).Repeat.Any(); // The Repeat.Any() is key. Otherwise the value wont be overridden.

  Assert.Throws<ArgumentException>(delegate { new Foo(fooLikeObjectStub); });
}

我发现的唯一警告是您不能执行两次。

This can be done using the Repeat.Any() construct.

I have not tested this using the SetupResult.For Syntax, but it works with the lambda syntax:

public IFooLikeObject CreateBasicIFooLikeObjectStub(MockRepository) {
  IFooLikeObject stub = MockRepository.GenerateStub<IFooLikeObject>();

  // These values are required to be non-null
  stub.Stub(s => s.FooLikeObject1).Return("AValidString");
  stub.Stub(s => s.FooLikeObject2).Return("AValidString2");
  stub.Stub(s => s.FooLikeObject5).Return("1");
  stub.Stub(s => s.FooLikeObject6).Return("1");
}

[Test]
void Constructor_FooLikeObject1IsNull_Exception() {
  IFooLikeObject fooLikeObjectStub = CreateBasicIFooLikeObjectStub();

  // This line no longer causes an exception
  stub.Stub(s => s.FooLikeObject1).Return(null).Repeat.Any(); // The Repeat.Any() is key. Otherwise the value wont be overridden.

  Assert.Throws<ArgumentException>(delegate { new Foo(fooLikeObjectStub); });
}

The only caveat I've found is you can't do it twice.

煞人兵器 2024-08-16 22:35:52

我可能错过了一些东西,但是你尝试过这样做吗?

var stub = mocks.Stub<IFooLikeObject>();

stub.FooLikeObject1 = "AValidString";
stub.FooLikeObject2 = "AValidString2";
stub.FooLikeObject5 = "1";
stub.FooLikeObject6 = "1";

使用存根,您可以直接将属性设置为您想要的内容。

如果该属性是只读的,您可以这样做:

var stub = mocks.Stub<IFooLikeObject>();

stub.Stub( x => x.FooLikeObject1).Return("AValidString");
stub.Stub( x => x.FooLikeObject2).Return("AValidString2");
stub.Stub( x => x.FooLikeObject5).Return("1");
stub.Stub( x => x.FooLikeObject6).Return("1");

I might be missing something, but have you tried just doing this?

var stub = mocks.Stub<IFooLikeObject>();

stub.FooLikeObject1 = "AValidString";
stub.FooLikeObject2 = "AValidString2";
stub.FooLikeObject5 = "1";
stub.FooLikeObject6 = "1";

With stubs, you can just set the properties to what you want them to be directly.

If the property is read only you could do it like this:

var stub = mocks.Stub<IFooLikeObject>();

stub.Stub( x => x.FooLikeObject1).Return("AValidString");
stub.Stub( x => x.FooLikeObject2).Return("AValidString2");
stub.Stub( x => x.FooLikeObject5).Return("1");
stub.Stub( x => x.FooLikeObject6).Return("1");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文