代码之家  ›  专栏  ›  技术社区  ›  MatthewMartin muthu

在C#中,如何在单元测试时模拟/伪造/替换/存根基类?

  •  2
  • MatthewMartin muthu  · 技术社区  · 15 年前

    更新:我改变了问题的措辞。以前,基类是否可以在运行时更改是一个“是/否”问题。

    我可能在做不可能完成的任务,但我似乎已经接近了。我想扩展一个ASP.NET控件,并且我希望我的代码是可单元测试的。另外,我希望能够伪造真实标签的行为(即ID生成等),而真实标签在nUnit主机中是做不到的。

    这里有一个工作示例,它对依赖于真实基类的内容和不依赖于真实基类的内容进行断言—在更现实的单元测试中,测试将同时依赖于这两个内容—即,现有的ID和一些自定义行为。

    不管怎么说代码比我说得好:

    public class LabelWrapper : Label //Runtime
    //public class LabelWrapper : FakeLabel //Unit Test time
    {
        private readonly LabelLogic logic= new LabelLogic();
    
        public override string Text
        {
            get
            {
                return logic.ProcessGetText(base.Text);
            }
            set
            {
                base.Text=logic.ProcessSetText(value);
            }
        }
    }
    
    //Ugh, now I have to test FakeLabelWrapper
    public class FakeLabelWrapper : FakeLabel //Unit Test time
    {
        private readonly LabelLogic logic= new LabelLogic();
    
        public override string Text
        {
            get
            {
                return logic.ProcessGetText(base.Text);
            }
            set
            {
                base.Text=logic.ProcessSetText(value);
            }
        }
    }
    
    [TestFixture]
    public class UnitTest
    {
        [Test]
        public void Test()
        {
            //Wish this was LabelWrapper label = new LabelWrapper(new FakeBase())
            LabelWrapper label = new LabelWrapper();
            //FakeLabelWrapper label = new FakeLabelWrapper();
            label.Text = "ToUpper";
            Assert.AreEqual("TOUPPER",label.Text);
            StringWriter stringWriter = new StringWriter();
            HtmlTextWriter writer = new HtmlTextWriter(stringWriter);
            label.RenderControl(writer);
            Assert.AreEqual(1,label.ID);
            Assert.AreEqual("<span>TOUPPER</span>", stringWriter.ToString());
        }
    }
    
    public class FakeLabel
    {
        virtual public string Text { get; set; }
        public void RenderControl(TextWriter writer)
        {
            writer.Write("<span>" + Text + "</span>");
        }
    }
    
    //System Under Test
    internal class LabelLogic
    {
        internal string ProcessGetText(string value)
        {
            return value.ToUpper();
        }
    
        internal string ProcessSetText(string value)
        {
            return value.ToUpper();
        }
    }
    
    2 回复  |  直到 15 年前
        1
  •  3
  •   JaredPar    15 年前

    想想这会造成多大的破坏。假装我有以下情况

    class Example  {
      Label l = new LabelWrapper();
    }
    

    这段代码已经执行,您的代码突然运行,切换了 LabelWrapper 成为 FakeLabel

    • Example ?
    • 如果出现新的 例子 因为这个代码现在是完全无效的?
    • 这带来了许多安全噩梦,因为我现在可以以API无法解释的方式动态地修改我的对象。
        2
  •  -1
  •   Marcel    12 年前

    我不太理解你的例子。但如果你想 部分 改变你的行为 LabelWrapper Moq .

    标签包装机 然而,这是非常不传统的。