Подписка на события RhinoMocks - PullRequest
2 голосов
/ 26 ноября 2008

Будучи новичком в RhinoMocks и модульном тестировании, я столкнулся с проблемой, которую, похоже, не могу решить (независимо от того, сколько документации я прочитал).

Проблема заключается в следующем: я создал интерфейс, который выставляет 5 событий (которые будут использоваться для представления в ASP.NET и шаблоне контролера MVP ..... Я знаю, я должен использовать MVC, но это совсем другой вопрос). В любом случае, я хочу проверить, что когда определенное событие запускается в представлении, мы назовем его «IsLoaded», что вызывается метод внутри моего Presenter, и, используя Dependency Injection, значение возвращается из Dependency и устанавливается в вид. Вот где начинается проблема: когда я использую Expect.Call (Dependency.GetInfo ()). Return (SomeList), Call никогда не выполняется (без вызова метода mock.ReplayAll ()). Хорошо, когда я вызываю метод ReplayAll, я получаю ExpectationExceptions из-за подписки объекта Presenter на другие события, предоставляемые интерфейсом представления.

Итак, чтобы проверить, что IView.IsLoaded сработал, я хочу убедиться, что IView.ListOfSomething обновлен в соответствии со списком, который я передал через Expect.Call (). Однако, когда я устанавливаю ожидание, другие подписки на события (которые происходят прямо из конструктора для докладчика) не соответствуют ожиданиям # 0 теста. Я получаю, view.Save + = this.SaveNewList отбрасывает исключение RhinoMocks ExpectationViolationException.

Мой вопрос на миллион долларов таков: нужно ли мне устанавливать ожидания для ВСЕХ моих событий (через [Setup]), или я чего-то упускаю / не понимаю, как работает Unit Testing или RhinoMocks?

Пожалуйста, имейте в виду, что я чрезвычайно новичок в модульном тестировании и, следовательно, RhinoMocks. Если окажется, что я не знаю, о чем говорю, пожалуйста, не стесняйтесь указывать на это.

1 Ответ

2 голосов
/ 03 декабря 2008

Я работаю над проектом, в котором мы также использовали макеты MVP и Rhino. Мы просто ожидали подписки на все события в каждом тесте.

    private void SetupDefaultExpectations()
    {
        _mockView.Initializing += null; LastCall.IgnoreArguments();
        _mockView.SavingChanges += null; LastCall.IgnoreArguments();
    }

Затем мы создали метод расширения для IMockedObject (из RhinoMocks) для запуска событий в модульных тестах и ​​развертывания исключений, чтобы их можно было ожидать стандартным способом NUnit.

static class IMockedObjectExtension
{
    public static void RaiseEvent(this IMockedObject mockView, string eventName, EventArgs args)
    {
        EventRaiser eventraiser = new EventRaiser(mockView, eventName);

        try
        {
            eventraiser.Raise(mockView, args);
        }
        catch (TargetInvocationException ex)
        {
            throw ex.InnerException;
        }
    }

    public static void RaiseEvent(this IMockedObject mockView, string eventName)
    {
        RaiseEvent(mockView, eventName, EventArgs.Empty);
    }
}

Это может быть использовано в модульном тесте, как это

using(_mocks.Record())
{
    Expect.Call(dependency.GetInfo()).Return(someList);
}
using(_mocks.Playback())
{
    Presenter presenter = new Presenter(_mockView, dependency);
    (_mockView as IMockedObject).RaiseEvent("SavingChanges");
}

Чтобы устранить дублирование между тестами презентаторов, мы реорганизовали это в базовый класс BasePresenterTest, который устанавливает эту базовую структуру для всех тестов презентаторов и предоставляет вспомогательные методы для подкласса.

public abstract class BasePresenterTest<VIEW> where VIEW : IBaseView
{
    protected MockRepository _mocks;
    protected VIEW View { get; private set; }

    protected abstract void SetUp();
    protected abstract void TearDown();
    protected abstract void SetupDefaultExpectations();

    [SetUp]
    public virtual void BaseSetUp()
    {
        _mocks = new MockRepository();
        View = _mocks.CreateMock<VIEW>();

        SetUp();
    }

    [TearDown]
    public virtual void BaseTearDown()
    {
        TearDown();

        View = null;
        _mocks = null;
    }

    protected virtual void BaseSetupDefaultExpectations()
    {
        //Setup default expectations that are general for all views
        SetupDefaultExpectations();
    }

    protected virtual IDisposable Record()
    {
        IDisposable mocksRecordState = _mocks.Record();

        BaseSetupDefaultExpectations();

        return mocksRecordState;
    }

    protected virtual IDisposable Playback()
    {
        return _mocks.Playback();
    }

    protected void RaiseEventOnView(string eventName)
    {
        (View as IMockedObject).RaiseEvent(eventName);
    }       
}

Это устраняет много кода из тестов в нашем проекте.

Мы по-прежнему используем старую версию RhinoMocks, но я постараюсь обновить ее после перехода на более позднюю версию.

...