MatthewMartin
MatthewMartin

Reputation: 33143

How do I mock/fake/replace/stub a base class at unit-test time in C#?

UPDATE: I've changed the wording of the question. Previously it was a yes/no question about if a base class could be changed at runtime.

I may be working on mission impossible here, but I seem to be getting close. I want to extend a ASP.NET control, and I want my code to be unit testable. Also, I'd like to be able to fake behaviors of a real Label (namely things like ID generation, etc), which a real Label can't do in an nUnit host.

Here a working example that makes assertions on something that depends on a real base class and something that doesn't-- in a more realistic unit test, the test would depend on both --i.e. an ID existing and some custom behavior.

Anyhow the code says it better than I can:

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();
    }
}

Upvotes: 2

Views: 1312

Answers (2)

Marcel
Marcel

Reputation: 15722

I do not understand your example quite well. But if you want to partially change the behavior of your LabelWrapper for unit tests, you could use Moq.

Moq is a Mocking framework which allows to setup your Mock with specific behavior on selected methods. This would mean you would test a mocked version of your LabelWrapper which is quite unconventional, however.

Upvotes: -1

JaredPar
JaredPar

Reputation: 754725

This is simply not possible in .Net. You cannot alter compiled meta-data on the fly.

Think of all of the havoc this would cause. Pretend I had the following situation

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

This code has executed and suddenly your code runs that switches the base type of LabelWrapper to be FakeLabel. This raises a number of very hairy problems, including but not limited to

  • What would happen to existing instances of Example?
  • What would happen to new instances of Example as this code is now completely invalid?
  • Number of security nightmares this introduces as I can now mutate my object on the fly in a way APIs can't account for.

Upvotes: 3

Related Questions