views:

213

answers:

5

I have a method that I want to test which expects an IEnumerable<T> as a parameter.

I'm currently mocking the contents of the IEnumerable<T> as follows (Using Moq):

 var mockParent = new Mock<ICsvTreeGridExportable>();
 var mockChild = new Mock<ICsvTreeGridExportable>();

How do it put these mocked objects inside an IEnumerable<T> so that I can pass them as a parameter to the method I want to test?

The method I'm testing expects to receive an IEnumerable<ICsvTreeGridExportable>

+8  A: 

I would just create an array using the collection intialiser syntax. i.e.

var mockParent = new Mock<ICsvTreeGridExportable>();
var mockChild = new Mock<ICsvTreeGridExportable>();

TestMethod(new[] { mockParent.Object, mockChild.Object });

Arrays in .NET implement the IEnumerable<T> interface, so you're all set.

Note: If you want a "pure" IEnumerable<T> (as Luke points out), you could use a little bit of LINQ to do that:

TestMethod((new[] { mockParent.Object, mockChild.Object }).TakeWhile(true));
Noldorin
yap... much simpler than my solution (+1)
sebastian
Noldorin, If you can change your answer to have mockParent.Object and mockChild.Object then I can mark this as the correct answer. Lukes answer below was also extreemly helpful. Shame I can't mark both as accepted :)
Jamie Dixon
@Jamie: Done. :)
Noldorin
+3  A: 

You could just create an array. (Arrays implement the IEnumerable<T> interface.)

var mockEnumerable = new[] { mockParent.Object, mockChild.Object };

If you want a "pure" IEnumerable<T> that can't be cast back to an array etc, then you could create it using a helper method:

var mockEnumerable = CreateEnumerable(mockParent.Object, mockChild.Object);

// ...

public static IEnumerable<T> CreateEnumerable<T>(params T[] items)
{
    foreach (T item in items)
    {
        yield return item;
    }
}

(As Jamie mentions in the comments, you need to use the mocked objects, not the Mock objects. For example, mockParent.Object, mockChild.Object etc, not just mockParent or mockChild.)

LukeH
Thanks Luke. When I try and pass my mockEnumerable to the method I get the following error: Argument.Type 'Moq.Mock<ICsvTreeGridExportable>[] is not assignable to parameter type IEnumerable<ICsvTreeGridExportable>.What do i need to do to make sure my mock objcts are of the right type?
Jamie Dixon
The `CreateEnumerable` method is exactly what I initially considered, but it doesn't really have any advantage over an array. The compiler generates a dummy class anyway, so meh. If however you want lazy initialisation (see sebastian's answer), it might be useful.
Noldorin
This still gives me the same issue. When i used IEnumerable<ICsvTreeGridExportable> x = CreateEnumerable(mockParent, mockChild); I'm still informed that "Cannot convert source type". One is of type IEnum...<ICsv...> and the other of type IEnum...<Moq.Mock<ICsv...>. I'm surely missing something very simple here.
Jamie Dixon
@Noldorin: Using a "pure" enumerable is handy for testing. I've seen methods that claim to take `IEnumerable<T>` but then blindly cast to `IList<T>` or similar internally. If you test those methods with an array or list then they'll pass, test with a "pure" `IEnumerable<T>` and you'll find those errors!
LukeH
@Jamie I'll take a look at that later maybe when I have some time. Anyway, does my solution not suffice?
Noldorin
@Luke: Haven't encountered that myself, but I'll take your word on it. If he's writing the method himself, it shouldn't be a problem though.
Noldorin
Ok I've figured it out with a lot of help from you guys. What I needed to do was add the mocked objects object to the array for use in my method. var mockEnumerable = new[] {mockParent.Object, mockChild.Object}; -- So i'm using mockParent.Object instead of just mockParent. This now casts to the right type for my method to accept. :)
Jamie Dixon
@Jamie: I was just about to suggest trying that. I'll update my answer for reference.
LukeH
+1  A: 

You could make something like this:
Create a function Dummy

private IEnumerable<ICsvTreeGridExportable> Dummy()
{
     yield return new ICsvTreeGridExportable();
}

And in your test function do something like

private void TestFunction()
{
   ThisIsTheOneThatNeedsIenumerable(Dummy());
}

hope it helps

sebastian
I think he wants to have an `IEnumerable` of more than one element.
Noldorin
yes, with the yield return you can return as many as you want... I missed that...
sebastian
@sebastian: Indeed. This method could however be useful if you want 'lazy initialisation' - i.e. only create the object when it is needed.
Noldorin
correct... +1 to the comment :)
sebastian
Isn't this `Dummy()` function going to provide a never-ending set of objects?
Dan Tao
nop... actually in the given example it would just return one single object
sebastian
A: 
List<ICsvTreeGridExportable> myList = new List<ICsvTreeGridExportable>();
myList.Add(mockParent);
myList.Add(mockChild);
return myList;
Josh Pearce
A: 

Here's an alternative to sebastian's answer that allows you to specify how many dummies of any type you want:

private IEnumerable<T> GetDummies<T>(int numDummies) where T : new() {
    for (int i = 0; i < numDummies; i++) yield return new T();
    yield break;
}

Or (if you want to use be able to use types without empty constructors):

private IEnumerable<T> GetDummies<T>(Func<T> generator, int numDummies) {
    for (int i = 0; i < numDummies; i++) yield return generator.Invoke();
    yield break;
}
Dan Tao