代码之家  ›  专栏  ›  技术社区  ›  patridge jonathanpeppers

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

  •  70
  • patridge jonathanpeppers  · 技术社区  · 17 年前

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

    至于任何一个模仿类型的瘾君子,我可能会建议我使用隔离:我很感激他们的努力,因为它看起来像是模仿类型的人可以蒙住眼睛喝醉,但我们的预算不会很快增加。

    5 回复  |  直到 8 年前
        1
  •  53
  •   Mendelt    17 年前

    扩展方法只是伪装的静态方法。模拟框架(如MOQ或Rhinomocks)只能创建对象的模拟实例,这意味着模拟静态方法是不可能的。

        2
  •  16
  •   Mike Fielden    16 年前

    我知道这个问题已经一年没有出现了,但是微软发布了一个框架来处理这个问题 Moles .

    这里还有一些教程:

  • DimeCasts.net
  • Nikolai Tillman's Tutorial
  •     3
  •  16
  •   informatorius    12 年前

    如果您可以更改扩展方法代码,那么您可以这样对其进行编码,以便能够测试:

    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<IMyImplementation>();
    
            MyExtensions.Implementation = mockMyImplementation.Object;
    
            var myObject = new Object();
            var myClassUsingExtensions = new MyClassUsingExtensions();
    
            // When:
            //-------
            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));
        }
    }
    
        4
  •  13
  •   larryq    13 年前

    我为需要模拟的扩展方法创建了一个包装类。

    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();
        }
    }
    

    然后,您可以模拟测试中的包装方法,并使用IOC容器编写代码。

        5
  •  3
  •   dmigo    11 年前

    对于扩展方法,我通常使用以下方法:

    public static class MyExtensions
    {
        public static Func<int,int, int> _doSumm = (x, y) => x + y;
    
        public static int Summ(this int x, int y)
        {
            return _doSumm(x, y);
        }
    }
    

    这使得注射非常容易。

    推荐文章