我试图为我的一个使用第三方库中的基类的类编写单元测试,但我的第一次尝试很脆弱,因为测试依赖于与内容管理员管理的文本的集成。 / p>
首先,一个小的复制品。这将代表我必须使用的第三方基类:
namespace ThirdPartyXyz
{
public class SomeFancyBaseClass
{
public SomeFancyBaseClass()
{
this.myMap = new Dictionary<string, string> { { "title", "Greatness" } };
}
public IReadOnlyDictionary<string, string> myMap { get; private set; }
}
}
然后我按照这些方式对代码进行单元测试:
namespace MyCorp
{
public class MyThing : ThirdPartyXyz.SomeFancyBaseClass
{
public string GetHeadline()
{
return "[" + this.myMap["title"] + "]";
}
}
}
使用以下NUnit测试方法:
namespace MyCorp.UnitTestExperiments
{
[TestFixture]
public class MyThingTests
{
[Test]
public void GetHeadlineWillOutputBracketedResource()
{
var thing = new MyThing();
var result = thing.GetHeadline();
Assert.That(result, Is.EqualTo("[Greatness]"));
}
}
}
这是绿色,但如果内容管理员将"Greatness"
值更改为其他值,则会变为红色。所以我试图从基类中模拟/存根/伪造实际的字典,但这并不简单,因为第三方库将myMap
的字典设置器声明为private
以下是我尝试的内容:
namespace MyCorp.UnitTestExperiments
{
[TestFixture]
public class MyThingTests
{
private class TestableMyThing : MyThing
{
public TestableMyThing(Dictionary<string, string> texts) { this.myMap = texts; }
public new IReadOnlyDictionary<string, string> myMap { get; private set; }
}
[Test]
public void GetHeadlineWillOutputBracketedResource()
{
var fakeTexts = new Dictionary<string, string> { { "title", "test text" } };
var thing = new TestableMyThing(fakeTexts);
var result = thing.GetHeadline();
Assert.That(result, Is.EqualTo("[test text]"));
}
}
}
但是,这不起作用:测试仍然失败。 GetHeadline
方法使用myMap
中隐藏的SomeFancyBaseClass
属性,而不是包含"test text"
的假字典。
目前我的目标/问题是双重的。首先,到目前为止,我很好奇我(c / w)应该如何让我当前的工作方式。但其次,我担心我MyThing
可测试的方式不是最好的,并且想知道是否有办法完全避免这种情况。
答案 0 :(得分:0)
三个选项:
使用反射来访问字典的set
第二个选项,让您的课程更容易存根:
public class MyThing : ThirdPartyXyz.SomeFancyBaseClass
{
public virtual new IReadOnlyDictionary<string, string> myMap;
{
get { return base.myMap; }
}
public string GetHeadline()
{
// this will use your 'virtual new myMap'!
return "[" + this.myMap["title"] + "]";
}
}
现在,在您的单元测试中,您可以:
public class MyThingTestable : MyThing
{
public override IReadOnlyDictionary<string, string> myMap { get; set; }
}
现在您可以设置myMap
,您的课程将使用它(但请注意SomeFancyBaseClass
课程不会使用它!它将使用其myMap
!不太好!)
第三种选择:使用Microsoft Fakes或类似产品。