There are many scenarios that need to be tested. There can be one or more words in the sentence. We should also test for an empty string. This can lead to many almost identical tests:
[Test]
public void MakeCamelCase_CalledWithEmptyString_ReturnsEmptyString()
{
// Arrange
var input = string.empty;
// Act
var result = StringTools.MakeCamelCase(input);
// Assert
Assert.AreEqual(string.empty, result);
}
[Test]
public void MakeCamelCase_CalledWithOneWord_ReturnsThatWord()
{
// Arrange
var input = "ab";
// Act
var result = StringTools.MakeCamelCase(input);
// Assert
Assert.AreEqual("Ab", result);
}
[Test]
public void MakeCamelCase_CalledWithTwoWords_ReturnsCamelCase()
{
// Arrange
var input = "ab cd";
// Act
var result = StringTools.MakeCamelCase(input);
// Assert
Assert.AreEqual("AbCd", result);
}
...and the list goes on. So how can we avoid repeating those almost identical tests?
TestCase
In NUnit, the test attribute TestCase comes to the rescue! Simply use one single test and provide multiple test cases as inputs:[TestCase(string.empty, string.empty)]
[TestCase("ab", "Ab")]
[TestCase("ab cd", "AbCd")]
[TestCase("ab cd ef", "AbCdEf")]
public void MakeCamelCase_CalledWithString_ReturnsCamelCase(string input, string expectedResult)
{
// Act
var result = StringTools.MakeCamelCase(input)
// Assert
Assert.AreEqual(expectedResult, result);
}
Now these three tests plus an additional test case with three words are collapsed to one single easy-to-read test.
Note that the [TestCase] attribute can take any number of parameters, including input and expected output. The test itself takes those parameters as input.
With NUnit 2.5 or newer, the input and result parameters can be made a bit more readable by using the named attribute parameter Result:
[TestCase(string.empty, Result = string.empty)]
[TestCase("ab", Result = "Ab")]
[TestCase("ab cd", Result = "AbCd")]
[TestCase("ab cd ef", Result = "AbCdEf")]
public string MakeCamelCase_CalledWithString_ReturnsCamelCase(string input)
{
// Act
var result = StringTools.MakeCamelCase(input)
return result;
}
TestCaseSource
All this is great, but [TestCase] has a limitation: it can only take constant expressions as parameters. If we were to test a mathematical algorithm on an input class like a Vector, we couldn't have used [TestCase]. There is another option, though: the TestCaseSource attribute:
[Test, TestCaseSource("VectorDotProductCases")]
public void DotProduct_CalledWithAnotherVector_ReturnsDotProduct(Vector lhs, Vector rhs, double expectedResult)
{
// Act
var dotProduct = lhs.DotProduct(rhs);
// Assert
Assert.AreEqual(expectedResult, dotProduct);
}
private static readonly object[] VectorDotProductCases =
{
new object[] { new Vector(1,2,3), new Vector(0,0,0), 0 },
new object[] { new Vector(1,2,3), new Vector(4,5,6), 32 },
};
This is slightly less readable than using TestCase, but still it's better than replicating the tests for each set of input data.
No comments:
Post a Comment