【问题标题】:How can I mock this static method我怎样才能模拟这个静态方法
【发布时间】:2015-10-30 13:27:13
【问题描述】:

我有这个代码:

public static bool IsValidVoucher(string id)
{
    //read tsv files
    var temp1 = AppData.GetAppData("stringval");            
    // code that need to be tested        
    return true;        
}

而且我喜欢创建单元测试,但是我怎样才能将 AppData.GetAppData("stringval") 模拟为我想要的任何值,以便我可以测试其余代码。

AppData 类是:

public class AppData
{
    public static object GetAppData(string name)
    {
        //...
    }
}

【问题讨论】:

  • 您可以注入一个读取 AppData 的类,然后在单元测试中模拟该类并设置您需要的返回值,而不是硬编码“AppData.GetAppData”。
  • 如果不进一步更改源代码,Moq 是不可能的。但是使用Typemock's Isolator 是可能的。但是隔离器不是免费的。
  • 还有here 更多关于模拟静态方法的信息。和here来自SO的回答。 HTH
  • 我放弃了我的答案,因为我相信它在这种情况下无济于事。无论如何,现在您知道表达式树有很大帮助!

标签: c# moq


【解决方案1】:

静态方法不能简单地模拟。你基本上有两种选择:

  1. 如果您拥有AppData 类,请更改实现以实现接口(例如IAppData)并删除GetAppData 方法上的static 修饰符,以便您可以模拟它。

    public interface IAppData
    {
        object GetAppData(string id);
    }
    
    public class AppData : IAppData
    {
        public object GetAppData(string id) {}
    }
    
    public class Foo
    {
        private readonly IAppData _appData;
    
        public Foo(IAppData appData)
        {
            _appData = appData;
        }
    
        public bool IsValidVoucher(string id)
        {
            // Call through object instance instead for class reference
            var temp1 = _appData.GetAppData("stringval");
        }
    }
    
  2. 如果您不拥有AppData 类,请使用实现接口的包装类(例如AppDataWrapper)并从IsValidVoucher 调用该方法:

    public interface IAppData
    {
        object GetAppData(string id);
    }
    
    public class AppDataWrapper : IAppData
    {
        public object GetAppData(string id)
        {
            return AppData.GetAppData(id);
        }
    }
    
    public class Foo
    {
        private readonly IAppData _appData;
    
        public Foo(IAppData appData)
        {
            _appData = appData;
        }
    
        public bool IsValidVoucher(string id)
        {
            var temp1 = _appData.GetAppData("stringval");
        }
    }
    

然后您可以使用 Moq 对 Foo 进行单元测试(此处以 xunit 为例):

public class FooTests
{
    private readonly IAppData _mockAppData;

    public FooTests()
    {
        var mockAppData = new Mock<IAppData>();
        mockAppData.Setup(m => m.GetAppData(It.IsAny<string>)).Returns("my test value");
        _mockAppData = mockAppData.Object;
    }

    [Fact]
    public void IsValidVoucher_ValidAppData_Returns()
    {
        var foo = new Foo(_mockAppData);
        // Unit test foo.IsValidVoucher
    }
}

【讨论】:

  • 你说静态方法不能被嘲笑......看我的回答;P也许这是一个疯狂的想法,但它有效!
  • @MatíasFidemraizer,我应该说静态方法不能以简单的方式模拟 ;) 为清晰起见进行了编辑
【解决方案2】:

嗯,我认为到目前为止每个人的 cmets 在技术上都是正确的 - 使用 RhinoMocksMoq 之类的东西,你真的不能以一种简单直接的方式模拟静态方法。

但是使用Moles,你绝对可以。因此,如果您有大量(当前)无法测试的代码驻留在静态方法中,我认为您应该研究 Moles。

(此链接有点过时,但我仍然觉得它很有帮助) http://research.microsoft.com/en-us/projects/pex/molesmanual.pdf

(关键文本)

Moles 可用于绕过任何 .NET 方法,包括密封类型中的非虚拟和静态方法。

工作原理:假设您有这样的典型情况:

public static class SomeStaticClass
{
    public static int SomeStaticMethod(string s)
    {
        return "Static method called: " + s;
    }
}

public class SomeInstanceClass
{
    public string SomeInstanceMethod(string s)
    {
        return SomeStaticClass.SomeStaticMethod(s);
    }
}

使用 Moles,您的测试代码将如下所示:

[TestMethod()]
[HostType("Moles")]
public void ShouldBeAbleToTestStaticMethod()
{
    var instance = new SomeInstanceClass();
    var testValue = instance.SomeInstanceMethod("Some test string");
    SomeStaticClass.SomeStaticMethod = (s) => "Moled you! " + s;
    Assert.That(testValue, Is.EqualTo("Moled you! Some test string"); // sorry, this has code smell, lol
}

当然,您需要将 Moles 设置到您的测试项目中,因此请务必查找 - 大量网络资源可以帮助您。

一些有用的帖子:

https://msdn.microsoft.com/en-us/library/ff798308.aspx

http://adventuresdotnet.blogspot.com/2011/03/mocking-static-methods-for-unit-testing.html

https://wannabeegeek.wordpress.com/2013/03/13/unit-testing-made-easy-with-moles-part-i/

【讨论】:

  • 我认为您至少应该在答案中显示一些代码,以展示 Moles 如何帮助对静态方法进行单元测试,而不是简单地发布各种资源的链接。
  • 摩尔仍然支持/可用吗?该网站似乎声明 Fakes 将取代它,并且假定的下载链接仅将我引导到 Moles 不存在的列表。我可能错过了下载链接?
  • 这是关于 MS Fakes 的当前 (VS 2017) 文档:docs.microsoft.com/en-us/visualstudio/test/… 不幸的是,Fakes 仅适用于 Visual Studio 的企业 SKU:visualstudio.com/vs/compare 至于 Moles,它似乎是最后一次支持的在 VS 2010 中:microsoft.com/en-us/research/project/…
猜你喜欢
  • 2011-01-31
  • 2015-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 2014-08-13
相关资源
最近更新 更多