Убедитесь, что событие было вызвано издевательским объектом

В моем модульном тесте, как я могу проверить, что событие вызывается издевательством над объектом.

У меня есть View(UI) --> ViewModel --> DataProvider --> ServiceProxy. ServiceProxy выполняет асинхронный вызов операции обслуживания. Когда асинхронная операция завершена, вызывается метод DataProvider (метод обратного вызова передается как параметр метода). Затем метод обратного вызова вызывает и событие, которое прослушивает ViewModel.

Для теста ViewModel я издеваюсь над DataProvider и проверяю, существует ли обработчик для события, вызванного DataProvider. При тестировании DataProvider я издеваюсь над ServiceProxy, но как я могу проверить, что вызывается метод обратного вызова и возникает событие.

Я использую синтаксис RhinoMock 3.5 и AAA.

Спасибо

-- Провайдер данных --

public partial class DataProvider
{
    public event EventHandler<EntityEventArgs<ProductDefinition>> GetProductDefinitionCompleted;

    public void GetProductDefinition()
    {
        var service = IoC.Resolve<IServiceProxy>();
        service.GetProductDefinitionAsync(GetProductDefinitionAsyncCallback);
    }

    private void GetProductDefinitionAsyncCallback(ProductDefinition productDefinition, ServiceError error)
    {
        OnGetProductDefinitionCompleted(this, new EntityEventArgs<ProductDefinition>(productDefinition, error));
    }

    protected void OnGetProductDefinitionCompleted(object sender, EntityEventArgs<ProductDefinition> e)
    {
        if (GetProductDefinitionCompleted != null)
            GetProductDefinitionCompleted(sender, e);
    }
}

-- ServiceProxy --

public class ServiceProxy : ClientBase<IService>, IServiceProxy
{
    public void GetProductDefinitionAsync(Action<ProductDefinition, ServiceError> callback)
    {
        Channel.BeginGetProductDefinition(EndGetProductDefinition, callback);
    }

    private void EndGetProductDefinition(IAsyncResult result)
    {
        Action<ProductDefinition, ServiceError> callback =
            result.AsyncState as Action<ProductDefinition, ServiceError>;

        ServiceError error;
        ProductDefinition results = Channel.EndGetProductDefinition(out error, result);

        if (callback != null)
            callback(results, error);
    }
}

person joblot    schedule 04.06.2010    source источник


Ответы (2)


Похоже, у вас есть два разных модульных теста для написания:

  1. Модульный тест Service Proxy: этот тест гарантирует, что обратный вызов, отправленный в ServiceProxy, будет вызван после завершения асинхронного вызова.

  2. Модульный тест поставщика данных: этот тест гарантирует, что при вызове определенного метода возникает событие (при условии, что есть несколько подписчиков).

По какому из них вы ищете помощи?

ИЗМЕНИТЬ:

Что касается пункта № 1, я не вижу, чтобы вам нужны были насмешки. Просто предоставьте обратный вызов, который устанавливает некоторую переменную в значение true при вызове:

// arrange
IServiceProxy serviceProxy = new ServiceProxy();
bool callbackMade;

// act
serviceProxy.GetDataAsync(() => callbackMade = true);

// assert
Assert.IsTrue(callbackMade);

Для пункта № 2 снова просто подпишитесь на событие в своем модульном тесте и убедитесь, что событие вызывается:

// arrange
DataProvider dp = new DataProvider();
bool eventRaised;
dp.DataReturned += (s,e) => eventRaised = true;

// act
dp.DoSomethingThatShouldRaiseEvent();

// assert
Assert.IsTrue(eventRaised)

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

person PatrickSteele    schedule 04.06.2010
comment
Извините за задержку. для 2-го теста проблема заключается в том, что DoSomethingThatShouldRiaseEvent не является общедоступным методом в DataProvider. Это метод обратного вызова, который передается в ServiceProxy. Благодарность - person joblot; 08.06.2010
comment
Вероятно, было бы полезно, если бы вы предоставили методы DataProvider и то, как они взаимодействуют с классом ServiceProxy. Я думаю, что разделение этого на два отдельных модульных теста — хорошее начало. Затем вы можете стать более изобретательным и соединить их в интеграционный тест (хотя сами по себе модульные тесты помогут убедиться, что отдельные компоненты ведут себя так, как задумано/ожидалось). - person PatrickSteele; 09.06.2010
comment
привет спасибо за ваш ответ. Я включил реализацию поставщика данных и сервисного прокси в исходный пост. DoSomethingThatShouldRiaseEvent (GetProductDefinitionAsyncCallback) не является общедоступным методом. Спасибо - person joblot; 17.06.2010
comment
Я не могу создать экземпляр ServiceProxy (это служба WCF), так как он жалуется на отсутствие файла конфигурации. Событие, если я добавлю конфигурацию, создание экземпляра завершится ошибкой, так как во время тестирования нет активной службы! - person joblot; 17.06.2010
comment
Во-первых: ваш конструктор DataProvider должен принимать экземпляр IServiceProxy. Вы не должны вызывать событие разрешения вашего контейнера вручную. Для DataProvider я бы сделал GetProductDefinitionAsyncCallback внутренним (вместо частного) и сделал его видимым для вашей сборки модульного тестирования с помощью атрибута InternalsVisibleTo. Это позволит вам вызвать метод, а затем убедиться, что событие было запущено. - person PatrickSteele; 17.06.2010
comment
Для ServiceProxy рассмотрите возможность абстрагирования класса Channel в интерфейс (IChannel). Это позволит вам внедрить макет в ServiceProxy и удалит вашу зависимость от внешнего ресурса (т.е. фактического канала WCF). - person PatrickSteele; 17.06.2010

В следующем примере устанавливается заглушка IService, которая просто вызывает любой обратный вызов, переданный ему при вызове IService.AsyncOperationWithCallBack(Action callback).

// arrange
var serviceStub = MockRepository.GenerateStub<IService>();
serviceStub.Stub(x => x.AsyncOperationWithCallBack(Arg<Action>.Is.NotNull))
    .WhenCalled(
        invokation =>
        {
            var callback = (Action)invokation.Arguments[0];
            callback();
        });

var dataProvider = new DataProvider(serviceStub);  

// act
bool raised = false;
dataProvider.MyEvent += delegate { raised = true; };
dataProvider.DoSomething();

// assert
serviceStub.AssertWasCalled(
    x=>x.AsyncOperationWithCallBack(Arg<Action>.Is.NotNull));
Assert.IsTrue(raised);
person Wim Coenen    schedule 04.06.2010