views:

813

answers:

3

Let's say I for example have this class that generates Fibonacci numbers:

public class FibonacciSequence : IEnumerable<ulong>
{
    public IEnumerator<ulong> GetEnumerator()
    {
        var a = 0UL;
        var b = 1UL;
        var c = a + b;
        while (true)
        {
            yield return c;
            c = a + b;
            a = b;
            b = c;
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

I can then write a test that makes sure that the n first numbers in the sequence are correct.

    [Test]
    public void GetEnumerator_FirstFifteenNumbers_AreCorrect()
    {
        var sequence = new FibonacciSequence().Take(15).ToArray();
        CollectionAssert.AreEqual(sequence, new[] {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610});
    }

When I check for coverage however, I will see that the IEnumerable.GetEnumerator() method is untested, and my coverage will be lower than it really needs to be. Fair enough. But how should I test that method?

How do you usually deal with this?

+1  A: 

You would have to use use IEnumerable (non-generic); I posted a reply using Cast<T>, but that will still cheat (it checked for the desired type as a special case) - you might need something like:

public static int CountUntyped(this IEnumerable source) {
    int count = 0;
    foreach(object obj in source) { count++; }
    return count;
}

IEnumerable<T> source = ...
Assert.AreEqual(typed.Count(), source.CountUntyped());
Marc Gravell
But that would just compare the count of items in the enumerables though, wouldn't it? And that would work kind of badly in my case, since the FibonacciSequence never really ends :p
Svish
Lol! Yes, I take your point there. But the thing I'm trying to highlight is working with `IEnumerable` rather than `IEnumerable<T>` - and I don't think you can simply use `Cast<T>`, 'cos it looks...
Marc Gravell
+2  A: 

EDIT: Updated based on what Marc said.

Well you could get the coverage up by doing:

// Helper extension method
public static IEnumerable AsWeakEnumerable(this IEnumerable source)
{
    foreach (object o in source)
    {
        yield return o;
    }
}

...

[Test]
public void GetEnumerator_FirstFifteenNumbers_AreCorrect()
{
    IEnumerable weak = new FibonacciSequence().AsWeakEnumerable();
    var sequence = weak.Cast<int>().Take(15).ToArray();
    CollectionAssert.AreEqual(sequence, 
        new[] {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610});
}

Note that weak is declared to be the nongeneric IEnumerable type... which means you need to call Cast on it to cast each returned object to int.

I'm not sure I'd bother though...

Jon Skeet
No - I checked, and `Cast<T>` actually checks via `as` for `IEnumerable<T>`, so you'll end up using `IEnumerable<T>.GetEnumerator()`, not `IEnumerable.GetEnumerator()`
Marc Gravell
That's what I saw too. So then I wasn't quite sure how to go about doing it, hehe.
Svish
Fixed, thanks guys - it's a case of wrapping the strong version in the weak...
Jon Skeet
Much better ;-p
Marc Gravell
Actually ended up doing something similar to this. And I figured I could just skip the whole Cast and Take thing too, just sent it into the CollectionAssert like it is. Back to 100% test coverage :p
Svish
What I ended up doing, since as I commented to Marc have some infinite sequences, was to implement a `Take` method for nongeneric `IEnumerable` :)
Svish
+1  A: 

I wouldn't test it. I would try to filter the method out of the coverage tool. I think coverage should check things I want to have covered and not everything. From other comments you seem to be using TestDriven.Net. I don't know how well that filters but it was possible with NCover. You could try PartCover also.

Mike Two
Of course, and I am not beating myself up over this or anything. Just curious to see how others deal with it :)
Svish
@Svish - sorry, the answer does sound snippier than I intended. But I would really look into filtering things out. I think it is better than trying to add a test for it.
Mike Two