Pregunta

In my class, i have declared a delegate type, I am creating an instance of it, and then calling BeginInvoke off of that instance:

public class ClassA
{
    ...
    public delegate bool MyDelegate(int x);
    ...
    public void MethodA()
    {
        ...
        var myDelegate = new MyDelegate(Foo);
        myDelegate.BeginInvoke(...);
        ...
    }
    ...
}

In writing unit tests for the MethodA, I don't actually ever want BeginInvoke to be called. What I want to do is use the Moles framework to mole out the BeginInvoke call. Normally, I'd try

MMyDelegate.AllInstances.BeginInvoke... = (...) => { /* something here */ }

but I have been unable to get moles to generate anything for the MyDelegate type.

According to http://msdn.microsoft.com/en-us/library/system.delegate.aspx, "The common language runtime provides each delegate type with BeginInvoke and EndInvoke methods". If this is the case, and BeginInvoke isn't even a method within the Delegate class (being provided by the CLR), is it even possible to mole it? Has anyone else had any luck in moling out BeginInvoke off of delegate types?

¿Fue útil?

Solución

I don't really know about Microsoft Moles but I tried to achieve the same with Microsoft Fakes (actually this is a heir of Microsoft Moles built in into the Visual Studio 2012 Premium and Ultimate).

When I tried to build Fake assembly (know Microsoft calls it Fakes and Shims instead of Moles and Stubs) I got following warning:

Warning 1   Cannot generate stub for AssemblyUnderTest.FooDelegate: type is sealed. d:\Sources\Projects\PlayingWithMoles\PlayingWithMoles\Fakes\AssemblyUnderTest.fakes
Warning 2   Cannot generate shim for AssemblyUnderTest.FooDelegate: type is a delegate. d:\Sources\Projects\PlayingWithMoles\PlayingWithMoles\Fakes\AssemblyUnderTest.fakes

(To get this warning you should turn off additional diagnostic in the fakes configuration file (I'm not sure that format is the same in Fakes and Moles):

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/" **Diagnostic="true"**>
  <Assembly Name="AssemblyUnderTest"/>
</Fakes>

But alas, this warning clearly stated that we can't do this. But we can avoid this issue at all by moving to another asynchronous API, for example to Task Parallel Library a.k.a. TPL.

Task (or Task of T) object itself represents asynchronous operation as a first class object that allows you to store this "async operation" in the field, return it from method or pass it around. This improves testability a lot because you can easily mock you implementation with fake one:

class SomeService
{
  Task<string> GetSomeResult()
  {
    // Performing long-running operation to obtain the result
  }
}

class YourServiceConsumer
{
  private void YourMethod()
  {
     Task<string> task = service.GetSomeResult();
  }
}

Than you can easily extract your dependency with separate interface and inject it into you YourServiceConsumer or fake it using Microsoft Moles (or Microsoft Fakes) without adding additional layers.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top