我正在编写一个依赖于扩展方法结果的测试,但我不希望该扩展方法的未来失败会破坏此测试.模拟这个结果似乎是显而易见的选择,但是Moq似乎没有提供一种覆盖静态方法的方法(扩展方法的要求).与Moq.Protected和Moq.Stub有类似的想法,但它们似乎没有为这种情况提供任何东西.我错过了什么或者我应该以不同的方式去做这件事吗?
这是一个简单的例子,通常会对"不可覆盖的成员的无效期望"失败.这是需要模拟扩展方法的一个不好的例子,但它应该这样做.
public class SomeType { int Id { get; set; } } var ListMock = new Mock>(); ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5)) .Returns(new SomeType { Id = 5 });
至于任何可能建议我使用Isolator的TypeMock迷们:我很欣赏这项努力,因为看起来TypeMock可能会被蒙住眼睛和醉酒,但我们的预算不会很快增加.
扩展方法只是伪装的静态方法.像Moq或Rhinomocks这样的模拟框架只能创建对象的模拟实例,这意味着无法模拟静态方法.
如果您可以更改扩展方法代码,那么您可以像这样编码以便能够测试:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; public static class MyExtensions { public static IMyImplementation Implementation = new MyImplementation(); public static string MyMethod(this object obj) { return Implementation.MyMethod(obj); } } public interface IMyImplementation { string MyMethod(object obj); } public class MyImplementation : IMyImplementation { public string MyMethod(object obj) { return "Hello World!"; } }
因此,扩展方法只是实现接口的包装.
(你可以只使用没有扩展方法的实现类,这些方法是一种语法糖.)
您可以模拟实现接口并将其设置为扩展类的实现.
public class MyClassUsingExtensions { public string ReturnStringForObject(object obj) { return obj.MyMethod(); } } [TestClass] public class MyTests { [TestMethod] public void MyTest() { // Given: //------- var mockMyImplementation = new Mock(); MyExtensions.Implementation = mockMyImplementation.Object; var myClassUsingExtensions = new MyClassUsingExtensions(); // When: //------- var myObject = new Object(); myClassUsingExtensions.ReturnStringForObject(myObject); //Then: //------- // This would fail because you cannot test for the extension method //mockMyImplementation.Verify(m => m.MyMethod()); // This is success because you test for the mocked implementation interface mockMyImplementation.Verify(m => m.MyMethod(myObject)); } }
我知道这个问题大约一年没有激活,但是微软发布了一个框架来处理这个名为Moles的问题.
这里有一些教程:
DimeCasts.net
尼古拉蒂尔曼的教程
我为我需要模拟的扩展方法创建了一个包装类.
public static class MyExtensions { public static string MyExtension(this T obj) { return "Hello World!"; } } public interface IExtensionMethodsWrapper { string MyExtension (T myObj); } public class ExtensionMethodsWrapper : IExtensionMethodsWrapper { public string MyExtension (T myObj) { return myObj.MyExtension(); } }
然后,您可以使用IOC容器模拟测试中的包装器方法和代码.