我该如何模拟这个静态方法

时间:2015-08-07 07:31:20

标签: c# moq

我有这段代码:

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)
    {
        //...
    }
}

2 个答案:

答案 0 :(得分:6)

无法以简单的方式模拟 。你基本上有两个选择:

  1. 如果您拥有AppData类,请更改实施以实现界面(例如IAppData)并删除static方法上的GetAppData修饰符,以便你可以嘲笑它。

    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");
        }
    }
    
  3. 然后,您可以使用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
        }
    }
    

答案 1 :(得分:1)

嗯,我认为到目前为止,每个人的评论在技术上都是正确的 - 使用类似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/