Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
258 views
in Technique[技术] by (71.8m points)

c# - How to change behaviour of stubs?

Can I change the behaviour of a stub during runtime? Something like:

    public interface IFoo { string GetBar(); }
    [TestMethod]
    public void TestRhino()
    {
        var fi = MockRepository.GenerateStub<IFoo>();
        fi.Stub(x => x.GetBar()).Return("A");
        Assert.AreEqual("A", fi.GetBar());
        fi.Stub(x => x.GetBar()).Return("B");
        Assert.AreEqual("B", fi.GetBar());    // Currently fails here
    }

My code example still fails in the given line, fi.GetBar() still returns "A".

Or is there another trick to model stubs whose behaviour changes over time? I'd rather not resort to using fi.Stub(...).Do(...).

Ah, probably I just need hardcopy of the fine manual for somebody to hit me over the head with it. It looks like it should really be obvious, but I can't find it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

WARNING

Changing the behaviour of stubs is a code smell!

It typically indicates that your unit tests are too complicated, are hard to understand and are brittle, breaking easily on correct changes of the class under test.

Check out:

  • [xUnit Test Patterns][1]
  • [The Art Of Unit Testing][2]

So, please: only use this solution if you can't avoid it. In my eyes this article borders on bad advice - however there are rare situations where you really need it.


Ah, I figured it out myself. Rhino supports record/replay mode. While AAA syntax always keeps the objects in replay mode we can switch to record and back to replay just to clear the stub's behaviour.

It looks a little hackish, however ...

    public interface IFoo { string GetBar(); }
    [TestMethod]
    public void TestRhino()
    {
        var fi = MockRepository.GenerateStub<IFoo>();
        fi.Stub(x => x.GetBar()).Return("A");
        Assert.AreEqual("A", fi.GetBar());

        // Switch to record to clear behaviour and then back to replay
        fi.BackToRecord(BackToRecordOptions.All);
        fi.Replay();

        fi.Stub(x => x.GetBar()).Return("B");
        Assert.AreEqual("B", fi.GetBar());
    }

Update:

I'll be using this in the future, so things look a little nicer:

internal static class MockExtension {
    public static void ClearBehavior<T>(this T fi)
    {
        // Switch back to record and then to replay - that 
        // clears all behaviour and we can program new behavior.
        // Record/Replay do not occur otherwise in our tests, that another method of
        // using Rhino Mocks.

        fi.BackToRecord(BackToRecordOptions.All);
        fi.Replay();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...