I use AutoData in my xUnit unit tests. I occasionally have a need for a particular number of objects to be supplied to my tests. Consider the following class:
public class Recipient
{
public void Receive(
CallingBird bird1,
CallingBird bird2,
CallingBird bird3,
CallingBird bird4
)
{
this.Bird1 = bird1;
this.Bird2 = bird2;
this.Bird3 = bird3;
this.Bird4 = bird4;
}
public CallingBird Bird1 { get; private set; }
public CallingBird Bird2 { get; private set; }
public CallingBird Bird3 { get; private set; }
public CallingBird Bird4 { get; private set; }
}
Without AutoData, I might write a test like this:
[Fact]
public void All_Birds_Are_Populated()
{
var bird1 = new CallingBird();
var bird2 = new CallingBird();
var bird3 = new CallingBird();
var bird4 = new CallingBird();
var sut = new Recipient();
sut.Receive(bird1, bird2, bird3, bird4);
Assert.NotNull(sut.Bird1);
Assert.NotNull(sut.Bird2);
Assert.NotNull(sut.Bird3);
Assert.NotNull(sut.Bird4);
}
Using AutoData in situations like this, I've been asking for an array of arrays of the object I need in order to get enough distinct instances (assume I need distinct instances) like this:
[Theory, Autodata]
public void All_Birds_Are_Populated(CallingBird[][] birds, Recipient sut)
{
sut.Receive(birds[0][0], birds[0][1], birds[0][2] ,birds[1][0]);
Assert.NotNull(sut.Bird1);
Assert.NotNull(sut.Bird2);
Assert.NotNull(sut.Bird3);
Assert.NotNull(sut.Bird4);
}
}
When you ask for arrays from AutoData, it gives you an array of 3 of those objects. So, if I need 4 of something, I could ask for 2 arrays, or an array of arrays (as shown), which in this example is more wasteful than asking for two arrays. It works, but I'm often asking for more instances to be supplied than I need. Imagine a situation in which the count is higher, the objects are more expensive to create, etc.
Can you suggest a cleaner way to ask for N objects of a type as a unit test parameter, where N is exactly the number I need?
Here's a proposed answer based on comments from Mark Seemann so far. I'll modify this as appropriate if this wasn't what he was hinting at...
It seems I may have been overthinking things a bit. If I need 4 CallingBird
instances for my SUT's method, then I can simply ask for those instances in separate parameters in the unit test signature like this:
[Theory, Autodata]
public void All_Birds_Are_Populated(
CallingBird bird1,
CallingBird bird2,
CallingBird bird3,
CallingBird bird4,
Recipient sut)
{
sut.Receive(bird1, bird2, bird3, bird4);
Assert.NotNull(sut.Bird1);
Assert.NotNull(sut.Bird2);
Assert.NotNull(sut.Bird3);
Assert.NotNull(sut.Bird4);
}
If the parameter list gets too long, then it may be identifying a code smell in my SUT's method signature. If it's not a code smell, then I should be able to tolerate at least the same number of parameters in my test method as I do in my SUT's method.
I suppose I could ask for arrays in the test method like in the OP to save space, but that's probably at the expense of showing clear intent.