tags:

views:

34

answers:

3

Hello :)

I would like to mock an interface that's passed in as the main argument to a function, but the method is complicated, and as a result I don't want to have to specify defaults or exact behavior for every test. I'd like to specify defaults in a Setup method, and override specific parts of that in each test as required.

I.e.:

public interface IOptions
{
    string Something { get; }
}

[TestFixture]
public class Tester
{
    MockRepository mocks;
    IOptions someOptions;
    string expectedXml;

    [Setup]
    public void Setup()
    {
        mocks = new MockRepository();
        someOptions = mocks.DynamicMock<IOptions>();
        //Something that would go here.
        // I.e. SetupResult.For(someOptions.Something).Return("default");
    }
    [Teardown]
    public void Teardown()
    {
        mocks.ReplayAll();
        using (var ms = new MemoryStream())
        {
            var unitUnderTest = new SomeOptionsWriter(ms);
            unitUnderTest.Write(someOptions);
            Assert.AreEqual(expectedXml, Encoding.Utf8.GetString(ms.ToArray()));
        }
        mocks.VerifyAll();
    }
    [Test]
    public void SomeTest()
    {
        expectedXml = "<root><default></default></root>";
        //Relies on default behavior
    }
    [Test]
    public void SomeTest2()
    {
        expectedXml = "<root><sub></sub></root>";
        Expect.Call(someOptions.Something).Return("sub");
    }
}

How can I accomplish this using Rhino Mocks?

A: 

Don't use record/replay semantics. Use AAA (Arrange/Act/Assert). In each test, you can use two lines of code to stub out your IOptions:

IOptions someOptions = MockRepository.GenerateStub<IOptions>();
someOptions.Stub(o => o.Something).Return("default");
Patrick Steele
How does one *not* use record/replay semantics with Rhino Mocks?
Billy ONeal
See the code sample shown above. I don't create a Mock Repository nor do I call any "Record" or "Replay" methods. I simply create a stub and set up a fake return value for a property. I can now pass this object to a method and it will work.
Patrick Steele
Ok. How does each individual test then override the behavior specified in the stub?
Billy ONeal
+1  A: 

In order to completely answer your question, I have to leap off @Patrick Steele's answer. Use the AAA setup. Declare your default stubs in the SetUp method and then override those stubs in specific Test methods. You won't be able to remove existing stubs unless you re-instantiate the object however.

The last stub added for a given function will override the previous.

someOptions.Stub(o => o.Something).Return("default");
someOptions.Stub(o => o.Something).Return("override");

The above stub in the example will return "override" when called.

ddc0660
How does one override the stub?
Billy ONeal
A: 

You can clear the behavior of a stub or mock as demonstrated in this other answer. Note that this will clear the behavior of all methods, not just one.

Wim Coenen
That sort of defeats the purpose of putting the defaults in the setup method though :(
Billy ONeal
@Billy ONeal: not if you create many stubs in the setup method.
Wim Coenen
@Wim: Hmm.. that assumes that the class I had to unit test was *well designed*, and not a 1600 line monster with one public method monstrosity which takes a class on which 80 methods need be mocked as a parameter :(
Billy ONeal