Consider the following test,
[Theory, MyConventions]
public void GetClientExtensionReturnsCorrectValue(BuilderStrategy sut)
{
var expected = ""; // <--??? the value injected into BuilderStrategy
var actual = sut.GetClientExtension();
Assert.Equal(expected, actual);
}
and the custom attribute I'm using:
public class MyConventionsAttribute : AutoDataAttribute {
public MyConventionsAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization())) {}
}
and the SUT:
class BuilderStrategy {
private readonly string _clientID;
private readonly IDependency _dependency;
public void BuilderStrategy(string clientID, IDependency dependency) {
_clientID = clientID;
_dependency = dependency;
}
public string GetClientExtension() {
return _clientID.Substring(_clientID.LastIndexOf("-") + 1);
}
}
I need to know what value was injected into the constructor parameter clientID
so that I can use it to compare with the output of GetClientExtension
. Is it possible to do this while still writing this style of test where the SUT is injected into the test method?
If you expose the injected clientID
(and dependency
as well) as read-only properties, you can always query their values:
public class BuilderStrategy {
private readonly string _clientID;
private readonly IDependency _dependency;
public void BuilderStrategy(string clientID, IDependency dependency) {
_clientID = clientID;
_dependency = dependency;
}
public string GetClientExtension() {
return _clientID.Substring(_clientID.LastIndexOf("-") + 1);
}
public string ClientID
{
get { return _clientID; }
}
public IDependency Dependency
{
get { return _dependency; }
}
}
This doesn't break encapsulation, but is rather known as Structural Inspection.
With this change, you could now rewrite the test like this:
[Theory, MyConventions]
public void GetClientExtensionReturnsCorrectValue(BuilderStrategy sut)
{
var expected = sut.ClientID.Substring(sut.ClientID.LastIndexOf("-") + 1);
var actual = sut.GetClientExtension();
Assert.Equal(expected, actual);
}
Some people don't like duplicating production code in the unit test, but I would rather argue that if you follow Test-Driven Development, it's the production code that duplicates the test code.
In any case, this is a technique known as Derived Value. In my opinion, as long as it retains a cyclomatic complexity of 1, we can still trust the test. Additionally, as long as the duplicated code only appears in two places, the rule of three suggests that we should keep it like that.