When unit testing for null or white space string variable, I often find myself writing the same unit test 3 times but with different input for the string parameter.
public class Sample { public static void RequiredStringParameter(string stringParam) { if (string.IsNullOrWhiteSpace(stringParam)) { throw new ArgumentException($"{nameof(stringParam)} is required."); } // Logics go here } } [TestFixture] public class SampleTests { [Test] public void Test_Null_StringParam_Should_Throw_Exception() { Assert.Throws<ArgumentException>(() => Sample.RequiredStringParameter(null)); } [Test] public void Test_Empty_StringParam_Should_Throw_Exception() { Assert.Throws<ArgumentException>(() => Sample.RequiredStringParameter(string.Empty)); } [Test] public void Test_WhiteSpace_StringParam_Should_Throw_Exception() { Assert.Throws<ArgumentException>(() => Sample.RequiredStringParameter(" ")); } }
Recently, I find a neat way to avoid having to write duplicate tests when testing the same behaviour with different inputs. NUnit test has the Values attribute for the parameter which allow you to define different inputs for the same test case.
The test fixture can be rewritten as below
[TestFixture] public class SampleTests { [Test] public void Test_Invalid_StringParam_Should_Throw_Exception([Values("", " ", null)] string value) { Assert.Throws<ArgumentException>(() => Sample.RequiredStringParameter(value)); } }
This is what’s shown in the test explorer.
If you add a second parameter with the Values attribute, for per value of the first parameter, NUnit will add a test for every value of the second parameter.
Another way to avoid having to write duplicate tests when testing the same behaviour with different inputs is to use TestCase attribute on the test itself.
[Test] [TestCase("")] [TestCase(null)] [TestCase(" ")] public void Test_Invalid_StringParam_Should_Throw_Exception(string value) { Assert.Throws<ArgumentException>(() => Sample.RequiredStringParameter(value)); }
You can also add more parameters if required.
[Test] [TestCase("", "ABC")] [TestCase(null, "ABC")] [TestCase(" ", "ABC")] public void Test_Invalid_StringParam_Should_Throw_Exception(string value, string testValue) { Assert.Throws<ArgumentException>(() => Sample.RequiredStringParameter(value)); }
The only thing I don’t like about these methods is that the values have to be constants. This means you cannot use string.Empty when setting the values for the input.