pat*_*dge 79 c# extension-methods moq mocking
我正在编写一个依赖于扩展方法结果的测试,但我不希望该扩展方法的未来失败会破坏此测试.模拟这个结果似乎是显而易见的选择,但是Moq似乎没有提供一种覆盖静态方法的方法(扩展方法的要求).与Moq.Protected和Moq.Stub有类似的想法,但它们似乎没有为这种情况提供任何东西.我错过了什么或者我应该以不同的方式去做这件事吗?
这是一个简单的例子,通常会对"不可覆盖的成员的无效期望"失败.这是需要模拟扩展方法的一个不好的例子,但它应该这样做.
public class SomeType {
int Id { get; set; }
}
var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
.Returns(new SomeType { Id = 5 });
Run Code Online (Sandbox Code Playgroud)
至于任何可能建议我使用Isolator的TypeMock迷们:我很欣赏这项努力,因为看起来TypeMock可能会被蒙住眼睛和醉酒,但我们的预算不会很快增加.
Men*_*elt 61
扩展方法只是伪装的静态方法.像Moq或Rhinomocks这样的模拟框架只能创建对象的模拟实例,这意味着无法模拟静态方法.
inf*_*ius 22
如果您可以更改扩展方法代码,那么您可以像这样编码以便能够测试:
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!";
}
}
Run Code Online (Sandbox Code Playgroud)
因此,扩展方法只是实现接口的包装.
(你可以只使用没有扩展方法的实现类,这些方法是一种语法糖.)
您可以模拟实现接口并将其设置为扩展类的实现.
public class MyClassUsingExtensions
{
public string ReturnStringForObject(object obj)
{
return obj.MyMethod();
}
}
[TestClass]
public class MyTests
{
[TestMethod]
public void MyTest()
{
// Given:
//-------
var mockMyImplementation = new Mock<IMyImplementation>();
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));
}
}
Run Code Online (Sandbox Code Playgroud)
ran*_*sen 12
我为我需要模拟的扩展方法创建了一个包装类.
public static class MyExtensions
{
public static string MyExtension<T>(this T obj)
{
return "Hello World!";
}
}
public interface IExtensionMethodsWrapper
{
string MyExtension<T>(T myObj);
}
public class ExtensionMethodsWrapper : IExtensionMethodsWrapper
{
public string MyExtension<T>(T myObj)
{
return myObj.MyExtension();
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用IOC容器模拟测试中的包装器方法和代码.