类方法在新的子类属性上选择隐藏的基类属性

时间:2015-05-21 08:42:28

标签: c# polymorphism

我试图为我的一个使用第三方库中的基类的类编写单元测试,但我的第一次尝试很脆弱,因为测试依赖于与内容管理员管理的文本的集成。 / 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可测试的方式不是最好的,并且想知道是否有办法完全避免这种情况。

1 个答案:

答案 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或类似产品。