猿问

如何使用Moq模拟扩展方法?

如何使用Moq模拟扩展方法?

我正在编写一个依赖于扩展方法结果的测试,但我不希望该扩展方法的未来失败会破坏此测试。模拟这个结果似乎是显而易见的选择,但是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 });

至于任何可能暗示我使用Isolator的TypeMock迷们:我很欣赏这项努力,因为看起来TypeMock可以完成蒙住眼睛和醉酒的工作,但我们的预算不会很快增加。


PIPIONE
浏览 540回答 3
3回答

白衣非少年

扩展方法只是伪装的静态方法。像Moq或Rhinomocks这样的模拟框架只能创建对象的模拟实例,这意味着无法模拟静态方法。

米琪卡哇伊

如果您可以更改扩展方法代码,那么您可以像这样编码以便能够测试:using&nbsp;System;using&nbsp;Microsoft.VisualStudio.TestTools.UnitTesting;using&nbsp;Moq;public&nbsp;static&nbsp;class&nbsp;MyExtensions{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IMyImplementation&nbsp;Implementation&nbsp;=&nbsp;new&nbsp;MyImplementation(); &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;string&nbsp;MyMethod(this&nbsp;object&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Implementation.MyMethod(obj); &nbsp;&nbsp;&nbsp;&nbsp;}}public&nbsp;interface&nbsp;IMyImplementation{ &nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;MyMethod(object&nbsp;obj);}public&nbsp;class&nbsp;MyImplementation&nbsp;:&nbsp;IMyImplementation{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;MyMethod(object&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;"Hello&nbsp;World!"; &nbsp;&nbsp;&nbsp;&nbsp;}}因此,扩展方法只是实现接口的包装。(你可以只使用没有扩展方法的实现类,这些扩展方法是一种语法糖。)您可以模拟实现接口并将其设置为扩展类的实现。public&nbsp;class&nbsp;MyClassUsingExtensions{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;ReturnStringForObject(object&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;obj.MyMethod(); &nbsp;&nbsp;&nbsp;&nbsp;}}[TestClass]public&nbsp;class&nbsp;MyTests{ &nbsp;&nbsp;&nbsp;&nbsp;[TestMethod] &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;MyTest() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Given: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//------- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;mockMyImplementation&nbsp;=&nbsp;new&nbsp;Mock<IMyImplementation>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyExtensions.Implementation&nbsp;=&nbsp;mockMyImplementation.Object; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;myObject&nbsp;=&nbsp;new&nbsp;Object(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;myClassUsingExtensions&nbsp;=&nbsp;new&nbsp;MyClassUsingExtensions(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;When: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//------- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myClassUsingExtensions.ReturnStringForObject(myObject); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Then: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//------- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;This&nbsp;would&nbsp;fail&nbsp;because&nbsp;you&nbsp;cannot&nbsp;test&nbsp;for&nbsp;the&nbsp;extension&nbsp;method &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//mockMyImplementation.Verify(m&nbsp;=>&nbsp;m.MyMethod()); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;This&nbsp;is&nbsp;success&nbsp;because&nbsp;you&nbsp;test&nbsp;for&nbsp;the&nbsp;mocked&nbsp;implementation&nbsp;interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mockMyImplementation.Verify(m&nbsp;=>&nbsp;m.MyMethod(myObject)); &nbsp;&nbsp;&nbsp;&nbsp;}}
随时随地看视频慕课网APP
我要回答