2

在我的类中,我声明了一个委托类型,我正在创建它的一个实例,然后从该实例调用 BeginInvoke:

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

在为 MethodA 编写单元测试时,我实际上并不希望调用 BeginInvoke。我想做的是使用 Moles 框架来消除 BeginInvoke 调用。通常,我会尝试

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

但我一直无法让痣为 MyDelegate 类型生成任何东西。

根据http://msdn.microsoft.com/en-us/library/system.delegate.aspx,“公共语言运行时为每个委托类型提供 BeginInvoke 和 EndInvoke 方法”。如果是这种情况,并且 BeginInvoke 甚至不是 Delegate 类中的一个方法(由 CLR 提供),是否有可能破坏它?有没有其他人有幸将 BeginInvoke 从委托类型中剔除?

4

1 回答 1

2

我不太了解 Microsoft Moles,但我尝试使用 Microsoft Fakes 来达到同样的效果(实际上这是 Visual Studio 2012 Premium 和 Ultimate 中内置的 Microsoft Moles 的继承者)。

当我尝试构建 Fake 程序集(知道 Microsoft 将其称为 Fakes and Shims 而不是 Moles 和 Stubs)时,我收到以下警告:

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

(要获得此警告,您应该在 fakes 配置文件中关闭附加诊断(我不确定 Fakes 和 Moles 中的格式是否相同):

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

但是很可惜,这个警告清楚地表明我们不能这样做。但是我们可以通过转移到另一个异步 API 来完全避免这个问题,例如转移到Task Parallel Library aka TPL

Task(或Task of T)对象本身将异步操作表示为第一类对象,它允许您将此“异步操作”存储在字段中,从方法返回或传递它。这大大提高了可测试性,因为您可以轻松地用假的来模拟您的实现:

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

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

您可以使用单独的接口轻松提取您的依赖项并将其注入您YourServiceConsumer或使用 Microsoft Moles(或 Microsoft Fakes)伪造它,而无需添加额外的层。

于 2012-11-29T20:58:23.120 回答