When I create a test:
[TestCase(123, "http://www.example.com/123")]
public void Foo(int clientId, string expectedUrl)
{
string url = GetUrl(clientId);
Assert.That(url, Is.EqualTo(expectedUrl));
}
I usually like to extract common elements in the input and the expected result. Specially if I use the same default value for several tests. For example, I like to do something like:
private int DefaultClientId = 123;
[TestCase(DefaultClientId , $"http://www.example.com/{DefaultClientId}")]
public void Foo(int clientId, string expectedUrl)
{
string url = GetUrl(clientId);
Assert.That(url, Is.EqualTo(expectedUrl));
}
However, this is not possible without using TestCaseSource
, which makes things much uglier for simple cases. The (even uglier?) solution I found is to declare a string variable with the “same” content:
private int DefaultClientId = 123;
private string DefaultClientIdValue = "123";
[TestCase(DefaultClientId , "http://www.example.com/" + DefaultClientIdValue)]
public void Foo(int clientId, string expectedUrl)
{
string url = GetUrl(clientId);
Assert.That(url, Is.EqualTo(expectedUrl));
}
Another option to overcome this problem is to do the string interpolation inside the function:
private int DefaultClientId = 123;
[TestCase(DefaultClientId , "http://www.example.com/")]
public void Foo(int clientId, string protoExpectedUrl)
{
var expectedUrl = protoExpectedUrl + DefaultClientId;
string url = GetUrl(clientId);
Assert.That(url, Is.EqualTo(expectedUrl));
}
but if I am testing several different TestCases and each of them produces a different url, that’s not possible.
Is there any way to handle this “problem” elegantly?
I can only suggest implementing custom attribute, that inherits from TestCaseAttribute
, that would prepare arguments correctly.
Implementation would be pretty simple:
public class TestCaseWithAppendingClientIdAttribute(int clientId, string expectedUrl)
: TestCaseAttribute(clientId, expectedUrl + clientId) { }
and then you could use in unit test:
[TestCaseWithAppendingClientId(DefaultClientId, "http://www.example.com/")]
public void Foo1(int clientId, string expectedUrl)
{
Assert.AreEqual(expectedUrl, $"http://www.example.com/{DefaultClientId}");
}
But you can make the attribute even more generic and account for any number of arguments, and also enabling them to be put into the string:
public class TestCaseWithInterpolationAttribute(string format, params object[] args)
// We need to put the formatted string as first argument, to keep the order of parameters passed to test method
: TestCaseAttribute(args.Prepend(string.Format(format, args)).ToArray()) { }
// Unit tests
[TestCaseWithInterpolation("http://www.example.com/{0}", DefaultClientId)]
public void Foo2(string expectedUrl, int clientId)
{
Assert.AreEqual(expectedUrl, $"http://www.example.com/{DefaultClientId}");
}
[TestCaseWithInterpolation("http://www.example.com/{0}/{1}", DefaultClientId, "edit")]
public void Foo3(string expectedUrl, int clientId, string path)
{
Assert.AreEqual(expectedUrl, $"http://www.example.com/{DefaultClientId}/edit");
}
Make your default id constant:
private const int DefaultClientId = 123;