0

我有一个服务代理类,可以对服务操作进行异步调用。我使用回调方法将结果传递回我的视图模型。

对视图模型进行功能测试,我可以模拟服务代理以确保在代理上调用方法,但是如何确保回调方法也被调用?

使用 RhinoMocks,我可以测试被模拟对象上的事件被处理和事件引发事件,但我如何测试回调?

视图模型:

public class MyViewModel
{
    public void GetDataAsync()
    {
        // Use DI framework to get the object
        IMyServiceClient myServiceClient = IoC.Resolve<IMyServiceClient>();
        myServiceClient.GetData(GetDataAsyncCallback);
    }

    private void GetDataAsyncCallback(Entity entity, ServiceError error)
    {
        // do something here...
    }

}

服务代理:

public class MyService : ClientBase<IMyService>, IMyServiceClient
{
    // Constructor
    public NertiAdminServiceClient(string endpointConfigurationName, string remoteAddress)
        :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    // IMyServiceClient member.
    public void GetData(Action<Entity, ServiceError> callback)
    {
        Channel.BeginGetData(EndGetData, callback);
    }

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

        ServiceError error;
        Entity results = Channel.EndGetData(out error, result);

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

谢谢

4

1 回答 1

1

玩了一下这个,我想我可能有你要找的东西。首先,我将显示我为验证这一点所做的 MSTest 代码:

[TestClass]
public class UnitTest3
{
    private delegate void MakeCallbackDelegate(Action<Entity, ServiceError> callback);

    [TestMethod]
    public void CallbackIntoViewModel()
    {
        var service = MockRepository.GenerateStub<IMyServiceClient>();
        var model = new MyViewModel(service);

        service.Stub(s => s.GetData(null)).Do(
            new MakeCallbackDelegate(c => model.GetDataCallback(new Entity(), new ServiceError())));
        model.GetDataAsync(null);
    }
}

public class MyViewModel
{
    private readonly IMyServiceClient client;

    public MyViewModel(IMyServiceClient client)
    {
        this.client = client;
    }

    public virtual void GetDataAsync(Action<Entity, ServiceError> callback)
    {
        this.client.GetData(callback);
    }

    internal void GetDataCallback(Entity entity, ServiceError serviceError)
    {

    }
}

public interface IMyServiceClient
{
    void GetData(Action<Entity, ServiceError> callback);
}

public class Entity
{
}

public class ServiceError
{
}

你会注意到一些事情:

  1. 我让你的回调内部。您将需要使用 InternalsVisisbleTo() 属性,以便您的 ViewModel 程序集向您的单元测试公开内部(我对此并不感到疯狂,但这种情况很少发生)。

  2. 每当调用 GetData 时,我都会使用 Rhino.Mocks “Do”来执行回调。它没有使用提供的回调,但这实际上更像是一个集成测试。我假设您已经进行了 ViewModel 单元测试,以确保传入 GetData 的真正回调在适当的时间执行。

  3. 显然,您将希望创建模拟/存根 Entity 和 ServiceError 对象,而不是像我那样只是新建。

于 2010-05-28T14:07:07.503 回答