Moq是一个具有内部属性并实现接口的类

本文关键字:属性 内部 实现 接口 一个 Moq | 更新日期: 2023-09-27 18:19:31

所以我有一个类,它既实现了一个接口,又有一个内部属性。我需要使用Moq来测试一种方法来模拟这两种情况。

public interface IMyObject
{
    bool myMethod (String input);
}
public class MyObject : IMyObject
{
    public bool myMethod(String input) {...}
    internal bool myProperty {get;}
}

现在,我可以使用Moq来嘲笑任何一个。

myMethod:

var myIObjectMock = mockRepository.Create<IMyObject>();
myIObjectMock.Setup(m => m.myMehtod(It.IsAny<String>())).Returns((String input) => {...});

myProperty:

var myObjectMock = mockRepository.Create<MyObject>();
myObjectMock.SetupGet(m => m.myProperty).Returns(...);

我的问题是,我该如何嘲笑两者?

问题的核心似乎是,我在第一种情况下嘲笑一个接口,在第二种情况下模仿一个类。因此,我看到的解决方案是使它能够通过模拟类或接口来模拟属性和方法。这意味着要么将内部属性转换为公共属性,并将其作为接口的一部分,要么使方法成为虚拟的。

有没有一个解决方案不涉及更改MyObject类?

Moq是一个具有内部属性并实现接口的类

第一个警告是,如果您的类定义和单元测试在不同的程序集中,并且它们可能在不同的组件中,那么您必须首先添加

[assembly: InternalsVisibleTo("<test project name>")]

到正在测试的程序集的AssemblyInfo.cs文件,以便内部属性甚至显示在单元测试程序集上。

至于Moq需要两个独立的对象,你可能不需要。使用上面中的示例

var mock = new Mock<MyObject>();
mock.As<IMyObject>().Setup(m => m.myMethod(It.IsAny<string>())).Returns(...);
mock.SetupGet(m => m.myProperty).Returns(...);

不幸的是,该设置将抛出NotSupportedException,因为myProperty不是虚拟的,Moq不支持嘲笑非虚拟成员。对于这种类型的功能,您必须查看不同的mocking库。

我认为接口上没有内部属性是一个警告,因为你似乎在等待类的某些副作用来设置它,这可能会导致竞争条件。一般来说,你应该保持你的属性不变,以避免这种困难。

你提到了解决这个问题的两种方法。侵入性最小的是将该方法虚拟化。另一种选择,添加另一个字段,也没有那么大风险。我只想做其中一个更改并完成它。你唯一能做的其他事情就是尝试通过接口在这个类上混合一个扩展方法,我强烈建议避免这样做。