使用 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")]
我有一个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")]