Passing other than array as arguments in parameterized tests.

Developer
Aug 14, 2011 at 6:36 PM

The following code works as expected and provides an array containing 3 elements:

 

[Theory, AutoControllerData]
public void FactoriesIsCorrectWhenInitializedWithArray(IControllerFactory[] factories)
{
}

 

However, if I pass an IEnumerable or an IList, it passes 0 elements:

[Theory, AutoControllerData]
public void FactoriesIsCorrectWhenInitializedWithArray(List<IControllerFactory> factories)
{
}

Coordinator
Aug 14, 2011 at 6:43 PM

http://blog.ploeh.dk/2011/02/08/CreatingGeneralPopulatedListsWithAutoFixture.aspx

Developer
Aug 14, 2011 at 7:18 PM
Edited Aug 15, 2011 at 12:43 AM

Whether I include the MultipleCustomization or not it creates an instance with 0 elements. However, with the array it creates an array of 3 elements (which is very, very helpful).

Coordinator
Aug 14, 2011 at 7:20 PM

How is the AutoControllerDataAttribute defined?

Developer
Aug 14, 2011 at 7:22 PM

public
class AutoControllerDataAttribute : AutoDataAttribute { public AutoControllerDataAttribute() : base(new Fixture().Customize(new ControllerCustomization())) { } } public class ControllerCustomization : CompositeCustomization { public ControllerCustomization() : base( new AutoMoqCustomization(), new MultipleCustomization()) { } }
Coordinator
Aug 14, 2011 at 7:26 PM

Try putting MultipleCustomization before AutoMoqCustomization... Actually, I don't quite understand why you are seeing what you report, but try switching them around and see if it helps.

Developer
Aug 14, 2011 at 7:32 PM

After switching them around it worked.

Coordinator
Aug 14, 2011 at 7:37 PM

In your first post you wrote that if you pass IEnumerable or IList the sequence is empty, yet in the example you provide you use the concrete List class, not the interfaces. Do you also see the original behavior with List<T>, or is it only with IEnumerable<T> and IList<T>?

Developer
Aug 14, 2011 at 7:44 PM

Before I switch around the customizations, the behavior was the same with IList<T> and List<T> (I got instances with 0 elements, not nulls).

However, after I switch around the customizations, (MultipleCustomization first, AutoMoqCustomization second), I got instances with 3 elements. Tested with IEnumerable<T>, IList<T>, List<T>, ICollection<T> and Collection<T>.

Coordinator
Aug 14, 2011 at 8:30 PM

Ah, it took me a while to understand why you'd see that behavior for List<T>, but for IList<T> and IEnumerable<T> it was expected. Let me start by explaining that and then the other reason follows:

The first Customization 'wins', which means that when you have AutoMoqCustomization first, it'll handle requests for IList<T> and IEnumerable<T> since they are interfaces. Moq will return a proxy instance of the requested interface where the enumerator by default (unless you configure it otherwise) emulates an empty list or sequence. In other words it didn't surprise me at all to see the reported behavior when IList<T> or IEnumerable<T> was requested.

When it comes to List<T> however, it did surprise me a little until I realized that what happens when List<T> is requested is that the MultipleCustomization selects this constructor to create an instance:

List<T>(IEnumerable<T>)

With the AutoMoqCustomization coming first, guess how the request for IEnumerable<T> is resolved :)

Switching the Customizations around is the idiomatic resolution to get the desired behavior.

Developer
Aug 14, 2011 at 9:22 PM
Now everything is clear :)

Thanks for providing such a detailed explanation.