2014-10-04 93 views
5

我有A类,我单元测试的方法,需要类B作为参数。类B是我试图模拟出来的,它是一个抽象类。这个类与下面类似。如何使用Moq模拟包含内部抽象方法的抽象类?

public abstract class B 
{ 
    internal abstract void DoSomething(); 
} 

我的单元测试看起来像。

[TestMethod] 
public void ClassA_Add_TestSomething() 
{ 
    var classA = new A(); 
    var mock = new Mock<B>(); 

    classA.Add(mock.Object); 

    // Assertion 
} 

我收到以下异常。

试验方法TestSomething抛出异常:
System.ArgumentException:类型嘲笑必须是一个接口或抽象的或不密封类。 ---> System.TypeLoadException:来自程序集“DynamicProxyGenAssembly2,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null”的类型为“Castle.Proxies.BProxy”的方法'DoSomething'没有实现。

我可以通过使方法虚拟而不是抽象来解决这个问题,但这不是我想用API设计完成的。我也曾尝试通过mock.Setup(m => m.DoSomething())来实施它,但无济于事。 Moq有可能吗?或者我将不得不创建一个从抽象类B派生的具体测试类?我想避免创建具体的类型,哪种类型的使用嘲弄或残留框架的目的失败了,还是我误导了这里?

编辑我发现如果我使方法public abstract不会发生此问题。所以我猜想真正的问题是,如果在使用InternalsVisibleTo和Moq时甚至可以使用内部方法。

+0

为什么不能使用mock.Setup? – brz 2014-10-04 20:26:57

+0

无论我是否使用安装程序,我都会收到异常。在我的单元测试中,我不在乎B.DoSomething是否有实现,尽管我明白为什么它需要一个实现。这可能是我没有正确使用'Setup',但我曾尝试过的是非常基本的'mock.Setup(m => m.DoSomething())。回调(()=> {});' – 2014-10-04 20:29:36

+4

仔细考虑为什么你在公开课上有一个“内部抽象”方法。其他人将无法实现抽象方法,因为它们不可见。也许这就是你想要的,虽然然后我会建议将构造函数作为内部函数,所以没有人会认为他们可以实现抽象类。 – 2014-10-04 20:38:57

回答

3

请仔细考虑为什么你在公共课堂上有一个internal abstract方法。其他人将无法实现抽象方法,因为它们不可见。也许这就是你想要的。有时,考虑到各种设计限制,这是一种有效的方法。如果你的图书馆将被其他人使用,我会推荐至少使构造函数成为内部的,所以没有人会认为他们可以实现抽象类。

5

Moq依靠Castle Dynamic Proxy来实现它的模拟。在运行时,将创建一个新程序集,并通过Moq将其加载到您的AppDomain中(出现在异常消息中的名称为DynamicProxyGenAssembly2)。

问题是此程序集无法访问内部类和您自己的代码的成员,因为它们在您声明它们的程序集外部是不可见的。

一个解决方法InternalsVisibleToAttribute来标记你的装配和动态指定生成的程序集的名字,可是

[InternalsVisibleTo("DynamicProxyGenAssembly2")] 

记住这个解决方案依赖于一个实现细节,并且可能会停止在未来的工作版本。

+2

这在一般情况下很有用,但在我的情况下,InternalsVisibleTo已经得到了适当的应用。问题在于Moq处理抽象类型的内部方法,具体而言。最终的答案是MikeZ所建议的,即重新考虑设计。作为@ DavidAnderson-DCOM提到的 – 2014-10-09 19:34:24

+1

,这种解决方案在这种情况下不起作用。我可以在我自己的测试中证实这一点。 – 2017-02-28 19:12:31