How do I reset the result for a property in a stub without resetting the entire stub?
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");
SetupResu开发者_开发百科lt.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?
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.
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");
精彩评论