Как мне протестировать метод, который нужно вызвать для настройки объекта перед тем, как тест будет запущен с использованием макетов Rhino? - PullRequest
0 голосов
/ 21 августа 2009

У меня проблемы с тестированием этого сценария.

Счет имеет два состояния - законченное и незаконченное - и я хочу проверить, что метод Presenter.FinishInvoice () вызывает DAO.FinishInvoice (), затем вызывает DAO.GetInvoice (), а затем устанавливает View.Invoice срезультат.Проблема в том, что мне нужно вызвать DAO.GetInvoice (), чтобы сначала закончить счет, и это вызывается из Presenter.InitializeView () (проверено в другом тесте).

Вот мой тест:

using (mocks.Record())
{
    SetupResult.For(view.Invoice).PropertyBehavior();
    SetupResult.For(DAO.GetInvoice(1)).Return(invoice);
    Expect.Call(DAO.FinishInvoice(1)).Return(true);
    Expect.Call(DAO.GetInvoice(1)).Return(invoice);
}
using (mocks.Playback())
{
    Presenter presenter = new Presenter(view, DAO);
    presenter.InitializeView(1);
    presenter.FinishInvoice();
}

Будет вызван DAO.GetInvoice (), а View.Invoice будет установлен один раз при вызове InitializeView ().Это не часть теста, но FinishInvoice () завершится ошибкой, если я не установлю View.Invoice на незавершенный счет, поэтому необходимо установить возвращаемое значение.

Второй вызов DAO.GetInvoice () вызывается из FinishInvoice (), и является частью теста.

Если я запускаю этот тест, я получаю ошибку приDAO.GetInvoice (1);Ожидаемый # 1, фактический # 0.Я прошел через код, и он вызывает DAO.GetInvoice (), когда вызывается FinishInvoice (), так что это должен быть мой тестовый код, который неисправен, а не мой код докладчика.

Если я изменю:

    SetupResult.For(DAO.GetInvoice(1)).Return(invoice);

до:

    Expect.Call(DAO.GetInvoice(1)).Return(invoice);

это работает, но это не должно быть частью теста, поскольку это просто необходимо для настройки (но не может быть помещено в метод SetUp какэто не требуется для всех тестов)

Я полагаю, что это не катастрофа, что мне нужно сделать это с Expect.Call (), но я хотел бы узнать, как настроить его так, как я хочу, чтобы оно было.

1 Ответ

0 голосов
/ 21 августа 2009

Так как вы хотите проверить взаимодействие вашего DAO-класса, вам нужно создать его как макет, а не как заглушку . Это означает, что вы не можете использовать SetupResult для этого.

Если вам не важен порядок вызовов методов, вы можете просто использовать Repeat-syntax :

using (mocks.Record())
{
    SetupResult.For(view.Invoice).PropertyBehavior();
    Expect.Call(DAO.FinishInvoice(1)).Return(true);
    Expect.Call(DAO.GetInvoice(1)).Return(invoice).Repeat.Any();
}
using (mocks.Playback())
{
    Presenter presenter = new Presenter(view, DAO);
    presenter.InitializeView(1);
    presenter.FinishInvoice();
}

Если вы заботитесь о порядке вызовов методов, вам придется явно указывать каждое ожидание с помощью Ordered-синтаксиса :

using (mocks.Record())
{     
    SetupResult.For(view.Invoice).PropertyBehavior();

    using (mocks.Ordered())
    {  
       Expect.Call(DAO.GetInvoice(1)).Return(invoice);     
       Expect.Call(DAO.FinishInvoice(1)).Return(true);
       Expect.Call(DAO.GetInvoice(1)).Return(invoice);
    }
}
using (mocks.Playback())
{
    Presenter presenter = new Presenter(view, DAO);
    presenter.InitializeView(1);
    presenter.FinishInvoice();
}

Однако, если вы дважды вызываете DAO.GetInvoice в своем коде, я бы сказал, что это запах кода, и вам, вероятно, стоит подумать о рефакторинге всего одного вызова.

Кроме того, вот как это будет выглядеть с синтаксисом AAA от 3.5 :

//Arrange
DAO.Stub( x => x.GetInvoice(1) ).Return(true).Repeat.Any();

//Act
Presenter presenter = new Presenter(view, DAO);
presenter.InitializeView(1);
presenter.FinishInvoice();

//Assert
DAO.AssertWasCalled( x => x.FinishInvoice(1) );
DAO.AssertWasCalled( x=> x.GetInvoice(1) );

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

...