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

时间:2010-03-23 19:47:49

标签: c# unit-testing

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

我可能在这里完成任务,但我似乎越来越近了。我想扩展一个ASP.NET控件,我希望我的代码可以单元测试。此外,我希望能够伪造真实标签的行为(即ID生成等内容),这是真正的标签在nUnit主机中无法做到的。

这是一个工作示例,它对依赖于真实基类的东西进行断言,而不是在更现实的单元测试中,测试将依赖于--i.e。现有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 个答案:

答案 0 :(得分:3)

这在.Net中根本不可能。您无法动态更改已编译的元数据。

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

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

此代码已执行,您的代码突然运行,将LabelWrapper的基本类型切换为FakeLabel。这引发了许多非常毛茸茸的问题,包括但不限于

  • Example的现有实例会怎样?
  • Example的新实例会发生什么情况,因为此代码现在完全无效?
  • 这引入的安全噩梦数量,因为我现在可以用API无法解释的方式动态改变我的对象。

答案 1 :(得分:-1)

我不太清楚你的例子。但是,如果您希望部分更改LabelWrapper单元测试的行为,则可以使用Moq

Moq是一个Mocking框架,它允许在选定的方法上设置具有特定行为的Mock。这意味着您将测试LabelWrapper的模拟版本,但这非常传统。