使用 Moq 验证是否已调用 void 方法

Verifying if a void method has been called using Moq

我有一个class负责制作导出的PPT幻灯片。为了对此进行单元测试,我创建了一个接口,以便可以使用 Moq 进行模拟;到目前为止一切都很好。但是,在尝试测试我的方法是否已被调用时,我 运行 遇到了困难。这是一个 void 方法,所以此时我只想知道该方法已被命中。

这是我的界面:

interface IPowerpointExporter
{
    void AddSlides(int amount);

    void setTitle(string title);
}

这是我的单元测试:

[TestMethod]
public void testPPTObject()
{
    var mockPPT = new Mock<IPowerpointExporter>();
    mockPPT.Setup(m => m.AddSlides(1)).Verifiable();
    mockPPT.Object.AddSlides(1);
    mockPPT.VerifyAll();
}

然而,当我打电话给 AddSlides() 时,我得到了一个 GeneratorException。对此的解释是我的 IPowerpointExporter 不可访问。我有一种感觉,这是因为我试图在接口上调用方法,但我不确定,因为此时我的对象位于 mockPPT.Object.AddSlides();

请注意,我还尝试了以下尝试使用实际对象而不是 Interface.Object。这也给出了同样的例外:

[TestMethod]
public void testPPTObject()
{
    var mockPPT = new Mock<IPowerpointExporter>();
    mockPPT.Setup(m => m.AddSlides(1)).Verifiable();

    ExportPowerPoint temp = (ExportPowerPoint)mockPPT.Object;
    temp.AddSlides(1);
    mockPPT.VerifyAll();
}

如何使用 Moq 检查我的方法是否已被调用?我在上面所做的是正确的吗?

您可能会遇到该异常,因为您的界面不是 public,或者对 Moq 程序集不可见。请参阅 解决该问题。

如果这只是帮助您学习 Moq 的虚拟代码,那么请不要继续阅读。


但是,如果这是您认为有价值的实际测试,那么您还有其他更根本的问题。在您的第一个示例中,您完全没有做任何测试代码的事情!让我们逐行检查它:

var mockPPT = new Mock<IPowerpointExporter>();

您创建了 IPowerpointExporter 界面的模拟,目前一切顺利。

mockPPT.Setup(m => m.AddSlides(1)).Verifiable();

您告诉 mock 期望调用它的 AddSlide 方法,参数为 1,并且可以验证该方法。目前没问题。

mockPPT.Object.AddSlides(1);

但这里是它离开 rails 的地方。您只是在模拟上调用该方法,与您在上面设置的相同。 Object 属性 是一个 虚拟对象 ,它只能执行它的设置, 与您的实际实现没有关系!

mockPPT.VerifyAll();

现在您验证了您调用了所有可验证的方法。您在此测试中所做的只是验证 Moq 是否有效;您的代码从未被触及。

现在让我们看看第二个示例中更改后的代码:

ExportPowerPoint temp = (ExportPowerPoint)mockPPT.Object;
temp.AddSlides(1);

该转换永远不会起作用。 Object 属性 只是一些代理(实际上是动态类型),由 Moq 生成,对它正在模拟的接口的任何具体实现。

发生此异常是因为 IPowerpointExporter 界面无法访问 Moq。

您可以使您的 IPowerpointExporter 界面 public,并且测试运行完美:

public interface IPowerpointExporter
{
    void AddSlides(int amount);

    void setTitle(string title);
}

....

[TestMethod]
public void testPPTObject()
{
    var mockPPT = new Mock<IPowerpointExporter>();
    mockPPT.Setup(m => m.AddSlides(1)).Verifiable();

    ExportPowerPoint temp = (ExportPowerPoint)mockPPT.Object;
    temp.AddSlides(1);
    mockPPT.VerifyAll();
}

但是,当您需要对非 public 类型进行测试时,您可以在程序集中使用 InternalsVisibleTo 属性使类型对 Moq 可见。

[assembly:InternalsVisibleTo("DynamicProxyGenAssembly2")]