Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialize object to test in SetUp or during the test method?

Tags:

unit-testing

I was wondering whether the object to test should be a field and thus set up during a SetUp method (ie. JUnit, nUnit, MS Test, …).

Consider the following examples (this is C♯ with MsTest, but the idea should be similar for any other language and testing framework):

public class SomeStuff
{
    public string Value { get; private set; }

    public SomeStuff(string value)
    {
        this.Value = value;
    }
}


[TestClass]
public class SomeStuffTestWithSetUp
{
    private string value;
    private SomeStuff someStuff;

    [TestInitialize]
    public void MyTestInitialize()
    {
        this.value = Guid.NewGuid().ToString();
        this.someStuff = new SomeStuff(this.value);
    }

    [TestCleanup]
    public void MyTestCleanup()
    {
        this.someStuff = null;
        this.value = string.Empty;
    }

    [TestMethod]
    public void TestGetValue()
    {
        Assert.AreEqual(this.value, this.someStuff.Value);
    }
}

[TestClass]
public class SomeStuffTestWithoutSetup
{
    [TestMethod]
    public void TestGetValue()
    {
        string value = Guid.NewGuid().ToString();
        SomeStuff someStuff = new SomeStuff(value);
        Assert.AreEqual(value, someStuff.Value);
    }
}

Of course, with just one test method, the first example is much too long, but with more test methods, this could be safe quite some redundant code.

What are the pros and cons of each approach? Are there any “Best Practices”?

like image 427
hangy Avatar asked Nov 19 '08 15:11

hangy


1 Answers

It's a slippery slope once you start initializing fields & generally setting up the context of your test within the test method itself. This leads to large test methods and really really unmanageable fixtures that don't explain themselves very well.

Instead, you should look at the BDD style naming & test organization. Make one fixture per context, rather than one fixture per system-under-test. Then your [setup] truly does setup the context, and your tests can be simple one-liner asserts.

It's much easier to read when you see a test output that does this:

OrderFulfillmentServiceTests.cs

  • with_an_order_from_a_new_customer

    • it should check their credit from the credit service
    • it should give no discount
  • with valid credit check

    • it should decrement inventory
    • it should ship the goods
  • with a customer in texas or california

    • it should add appropriate sales tax
  • with an order from a gold customer

    • it should NOT check credit
    • it should get expedited shipping added for free

Our tests are now really good documentation for our system. Each "with_an..." is a test fixture, and the items below it are tests. Within those, you setup the context (the state of the world as the class name describes) and then the test does the simple assert that verifies what the method name says it does.

like image 168
Ben Scheirman Avatar answered Oct 04 '22 03:10

Ben Scheirman