views:

47

answers:

3

Hi,

I'm using MSTest for testing and when I want to apply more inputs then the test looks like this:

[TestMethod]
public void SumTest()
{
  // data to test
  var items = new [] {
    new { First = 1, Second = 1, Expected = 2 },
    new { First = -1, Second = 1, Expected = 0 },
    new { First = 1, Second = 2, Expected = 3 },
    new { First = 1, Second = -1, Expected = 0 },
  };

  ICalculator target = GetSum(); // can be in the loop body

  foreach(var item in items)
  {
    var actual = target.Sum(item.First, item.Second);
    Assert.AreEqual(item.Expected, actual);
  }
}

I feel that this kind of testing is not the right way. I.e. I would like to separate testing data generation and testing itself.

I know, there is "data driven test" support in MSTest but it isn't sufficient for me:

  1. The items collection cannot be generated using some algorithm.
  2. I cannot use non-primitive types.

So what is your suggestion for this kind of tests?

I would like to have something like this but I'm not sure if this is the right way and if some testing framework supports this scenario.

[TestData]
public IEnumerable<object> SumTestData()
{
  yield return new { First = 1, Second = 1, Expected = 2 };
  yield return new { First = -1, Second = 1, Expected = 0 };
  yield return new { First = 1, Second = 2, Expected = 3 };
  yield return new { First = 1, Second = -1, Expected = 0 };
}

[TestMethod(DataSource="method:SumTestData")]
public void SumTest(int first, int second, int expected)
{
  // this test is runned for each item that is got from SumTestData method
  // (property -> parameter mapping is no problem)
  ICalculator target = GetSum();
  var actual = target.Sum(first, second);
  Assert.AreEqual(expected, actual);
}
+1  A: 

NUnit supports that scenario:

public IEnumerable SumTestData() {
    var cases = new List<TestCaseData>();
    cases.Add(new TestCaseData(1, 1, 2));
    cases.Add(new TestCaseData(-1, 1, 0));
    cases.Add(new TestCaseData(1, 2, 3));
    cases.Add(new TestCaseData(1, -1, 0));
    return cases
}

[Test]
[TestCaseSource("SumTestData")]
public void SumTest(int first, int second, int expected) {
}

The parameters can be any type. The TestCaseData constructor takes a param array of objects, so you just have to make sure that your test values are castable to the actual test method parameter types.

Christian Hayter
A: 

MSTest (and NUnit) allows you to identify methods that are run either before each test or when the test class is instantiated.

So you can extract a method that sets up your test data and have it run before your tests are run.

In MSTest you can use the TestInitializeAttribute to identify a method that is run before each test and you can use the ClassInitializeAttribute to identify a method that is run once when the test class is created.

Rune Grimstad
+2  A: 

http://xunit.codeplex.com/ can do such stuff: see [Theory] attribute details http://xunit.codeplex.com/wikipage?title=Comparisons

looks something like this:

        [Theory]
        [InlineData(SourceType.BackupFile, "RestoreMode")]
        [InlineData(SourceType.ExistingDatabase, "MonitorMode")]
        public void ShouldShowProperReportDependentOnSource(SourceType sourceType, string commandMode)
        {...}
dmitko