Question

I have a service proxy class that makes asyn call to service operation. I use a callback method to pass results back to my view model.

Doing functional testing of view model, I can mock service proxy to ensure methods are called on the proxy, but how can I ensure that callback method is called as well?

With RhinoMocks I can test that events are handled and event raise events on the mocked object, but how can I test callbacks?

ViewModel:

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...
    }

}

ServiceProxy:

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

Thanks

Was it helpful?

Solution

Played around with this a bit and I think I may have what you're looking for. First, I'll display the MSTest code I did to verify this:

[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
{
}

You'll notice a few things:

  1. I made your callback internal. You'll need to use the InternalsVisisbleTo() attribute so your ViewModel assembly exposes internals to your unit tests (I'm not crazy about this, but it happens in rare cases like this).

  2. I use Rhino.Mocks "Do" to execute the callback whenever the GetData is called. It's not using the callback supplied, but this is really more of an integration test. I assume you've got a ViewModel unit test to make sure that the real callback passed in to GetData is executed at the appropriate time.

  3. Obviously, you'll want to create mock/stub Entity and ServiceError objects instead of just new'ing up like I did.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top