Как изменить поведение заглушек? - PullRequest
18 голосов
/ 10 марта 2009

Можно ли изменить поведение заглушки во время выполнения? Что-то вроде:

    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
    }

Мой пример кода все еще терпит неудачу в данной строке, fi.GetBar() все еще возвращает "A".

Или есть еще одна хитрость для моделирования заглушек, поведение которых меняется со временем? Я бы предпочел не прибегать к использованию fi.Stub(...).Do(...).

Ах, наверное, мне просто нужна распечатка прекрасного руководства, чтобы кто-нибудь ударил меня им по голове. Похоже, это действительно должно быть очевидно, но я не могу его найти.

1 Ответ

27 голосов
/ 10 марта 2009

ПРЕДУПРЕЖДЕНИЕ

Изменение поведения заглушек - это запах кода!

Как правило, это означает, что ваши юнит-тесты слишком сложны, трудны для понимания и хрупки, легко ломаются при корректных изменениях тестируемого класса.

Выезд:

  • [Тестовые таблицы xUnit] [1]
  • [Искусство модульного тестирования] [2]

Итак, пожалуйста: используйте это решение, только если вы не можете его избежать . На мой взгляд, эта статья граничит с дурным советом - однако в редких случаях он вам действительно нужен.


Ах, я понял это сам. Rhino поддерживает режим записи / воспроизведения. В то время как синтаксис AAA всегда держит объекты в режиме воспроизведения, мы можем переключиться на запись и вернуться к воспроизведению, чтобы просто очистить поведение заглушки.

Это выглядит немного хакерским, однако ...

    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());
    }

Обновление:

Я буду использовать это в будущем, поэтому все выглядит немного лучше:

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();
    }
}
...