Moq是无法直接模拟静态方法的,解决方式有两种:
1、需要修改正式代码,在源代码中建一个新的方法把静态方法包起来,调用的时候源代码调用时调用新方法而不是原来的静态方法。
在测试的时候,Mock掉这个新的方法,以达到模拟的目的
原来:
public class FormatClass { public static string FormatDate(DateTime date) { return date.ToString("yyyyMMdd"); } } public class DoClass { public void Do() { var dateString = FormatClass.FormatDate(DateTime.Now); Console.WriteLine(dateString); } } [TestClass] public class Test { [TestMethod] public void MyTest() { var mock = new Mock<DoClass>(); mock.Object.Do(); } }
替换后:
public class FormatClass { public static string FormatDate(DateTime date) { return date.ToString("yyyyMMdd"); } } public class DoClass { public void Do() { var dateString = DefineFormatDate(DateTime.Now); Console.WriteLine(dateString); } //包装一个方法用于Mock public virtual string DefineFormatDate(DateTime date) { return FormatClass.FormatDate(date); } } [TestClass] public class Test { [TestMethod] public void MyTest() { var mock = new Mock<DoClass>(); //Mock方法 mock.Setup(a => a.DefineFormatDate(It.IsAny<DateTime>())).Returns("mock content"); mock.Object.Do(); } }
2、由于Mircosoft Fakes框架可以使用Shim模拟静态方法,那么我们可以将Moq和Fakes配合起来,用Fakes模拟静态方法,其他判断还用Moq
[TestClass] public class Test { [TestMethod] public void MyTest() { var mock = new Mock<DoClass>(); //未Shim之前 mock.Object.Do(); using (ShimsContext.Create()) { DFYYDream.Infrastructure.Fakes.ShimPinYinConvert.ConvertToPinYinStringBoolean = (String, Boolean) => { return "mock content"; }; //已经Shim之后 mock.Object.Do(); } //moq可以正常判断 mock.Verify(a => a.DoOther2(), Times.AtLeast(2)); } } public class DoClass { public void Do() { //一个中文转拼音的静态方法 var py = PinYinConvert.ConvertToPinYin("你好", false); DoOther(py); DoOther2(); } public void DoOther(string py) { Console.WriteLine(py); } public virtual void DoOther2() { } }
测试结果:
NIHAO
mock content
代码里的DFYYDream.Infrastructure.Fakes命名空间,是通过右击“引用”里的程序集的名称后,选择“添加Fakes程序集”自动生成的。
总结:
第一种方法不需要引入Fakes,但需要修改调用处的源代码
第二种方法不需要改把源代码,只需要在测试处模拟即可,但需要引入Fakes