我有这段代码:
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)
{
//...
}
}
答案 0 :(得分:6)
无法以简单的方式模拟 。你基本上有两个选择:
如果您拥有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");
}
}
如果您不拥有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
}
}
答案 1 :(得分:1)
嗯,我认为到目前为止,每个人的评论在技术上都是正确的 - 使用类似RhinoMocks
或Moq
的内容,你真的可以轻松,直接地模拟静态方法。
但是使用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/