tags:

views:

343

answers:

4

If I have the following code:

[TestFixture]
public class MyBaseTest
{
    protected ISessionManager _sessionManager;

    [SetUp]
    public void SetUp() { /* some code that initializes _sessionManager */ }
}

[TestFixture]
public class MyDerivedTest : MyBaseTest
{
    IBlogRepository _repository;

    [SetUp]
    public void SetUp() { /* some code that initializes _repository */ }

    [Test]
    public void BlogRepository_TestGoesHere() { /* some tests */ }
}

...NUnit doesn't call the base SetUp routine. This is expected, and I don't have a problem with it in itself. I can get the derived SetUp to call the base SetUp first, like this:

[TestFixture]
public class MyDerivedTest : MyBaseTest
{
    IBlogRepository _repository;

    [SetUp]
    public new void SetUp()
    {
        base.SetUp();
        /* some code that initializes _repository */
    }

This is ugly. If it was a constructor, I wouldn't have to.

I could use the "template method" pattern, and have the following:

public void MyBaseTest
{
    abstract void SetUp();

    [SetUp]
    public void BaseSetUp()
    {
        /* base initialization */
        SetUp(); // virtual call
    }
}

I'm not particularly fond of this, either.

What do you do when their test classes need SetUp, and they're derived from another class that also needs SetUp?

+4  A: 

You have to call the method directly.

   [SetUp]
   public void DerivedSetUp()
   {
      base.BaseSetUp();
      // Do something else
   }

Edit: I haven't tried it, but perhaps a partial method might work too. I'd prefer to do the above though.

Edit2: I've just tried using partial methods. It didn't work. Even if it did, I think it's still going to be easier to call the base class.

IainMH
I know. I don't want to.
Roger Lipscombe
Partial Method then? Because the SetUp is decorated with and attribute, I'm not sure there'd be too many more ways of doing it.
IainMH
Ooh. Didn't think of partial methods. Interesting approach.
Roger Lipscombe
I don't know if partial methods are going to work. They are private and can't be overriden...http://msdn.microsoft.com/en-us/library/wa80x488.aspx
Jason Punyon
@JPunyon - I think you're right. I've just tried it on a spike. Even if they did work, I think it would still be easier and clearer to call the base method directly.
IainMH
+3  A: 

You have the base class explicitly. Given that NUnit uses the [Setup] attribute to mark up test setup, I tink this is "the right thing" to do for NUnit, because it follows the usual language rules.

Sure, NUnit could search the base classes, and call their Setup functions automagically, but I think this would be rather surprising for most people.

There is however at least one unit testing framework that uses constructors for setup: xUnit.Net. Here, the base class setup is called automatically, because this is how constructors in C# behave.

(Note, though, that xUnit.Net recommends again using test setup.)

oefe
A: 

The following works in MbUnit. It may work in NUnit as well.

[TestFixture]
public abstract class Base {
    [SetUp]
    public virtual void SetUp() {
        //Some stuff.
    }
}

public class Derived : Base {
    public override void SetUp() {
        base.SetUp();
        //Some more stuff.
    }
    [Test]
    public virtual void Object_WhenInACertainState_WhenAMethodIsCalled_Throws() {
        //Create and set state on the object.
        //Call the method.
        //Assert the method threw.
    }
}
Justice
A: 

An approach that I use that I learned in the TDD FireStarter in Tampa was to have the setup method in the base class and then to have a virtual method in the base class called observe. This method is then called in the base class at the end of the setup method.

Then what you do is in the new class that derives from the base class you will override the observe method. The trick in this scenario is you want to execute the Setup method of the base class and the child class does not have a Setup method. The reason for this is the code that you have in the observe method are only those additional things you need for the child test class.

This approach works well for me, but one gotcha is that the test runner will want to execute the base class tests, so what I do to get around that is to move the Tests from the base class into a new class that derives from the base if I have any.

Michael Mann
That's the "template method" pattern I mention in my question. Good to know that some camps recommend it, though.
Roger Lipscombe