1

I am learning to use/perform/write tests for my code and started using FakeItEasy for my fake/mock objects, now I have encountered a problem :

I have the following class that implements IEnumerable and internal class that implements IEnumerator (not complete code below) :

public interface IEnumarableString : IEnumarable
{ }

public class AdvancedString : IEnumarableString
{
    private string[] _strings;
    private class StringEnumerator : IEnumerator
    {
            private IEnumerator GetEnumerator()
            {
                return (IEnumerator)this;
            }

            public object Current {get; set;}

            public bool MoveNext()
            {
                _position++;
                return _position < strings.Length;
            }

            public void Reset()
            {
                _position = -1;
            }
    }
    public IEnumerator GetEnumerator()
    {
           return new StringEnumerator(_strings);
    }
}

I want to use FakeItEasy on my tests and "fake" its iterative behavior, I tried the following code but it does not iterate through itself when it needs to (just skip the foreach like there are no elements) :

IEnumarableString stringFake = A.Fake<IEnumarableString>();

A.CallTo(() => stringFake.GetEnumerator().MoveNext()).Returns(false).Once();
A.CallTo(() => stringFake.GetEnumerator().MoveNext()).Returns(true).Once();

tried to search the net for example but could not find any. for now my question is how do I configure the stringFake.GetEnumerator() to return the right object so the iteration will work or am I doing something wrong here ?

Any help would be appreciated.

Thanks

DROP TABLE users
  • 1,955
  • 14
  • 26
yshuki
  • 55
  • 1
  • 5
  • 1
    Why are you not using `IEnumerable`? – Tim S. Dec 26 '13 at 15:17
  • `Current` is null always ? – Sriram Sakthivel Dec 26 '13 at 15:21
  • @TimS - because i need some extra functionality that IEnumarable does not supply, this is not the entire class just the relevant parts – yshuki Dec 26 '13 at 15:51
  • @SriramSakthivel - not sure I understand your question but (in the tests) when code reach a foreach statement it goes in but then skip like _strings is empty – yshuki Dec 26 '13 at 15:51
  • 4
    What actually are you trying to test? If you want to test your enumerable class itself, why mock anything? If you want to provide mock enumeration to something else, why not just provide a list as it should look like if all the enumeration logic is in place, and see how the consumer works? – Sunny Milenov Dec 26 '13 at 18:06
  • @SunnyMilenov - I am passing it as a parameter to another class, since I want to test the other class and I want to use a mock/fake and not the real object (to learn proper testing, and because I want to test only my target class), the class allow me to iterate a string as if its made of a string array or treat it as 1 long string – yshuki Dec 29 '13 at 14:36

2 Answers2

2

If you can't just provide a concrete IEnumerable<string> as @TimS suggested, because you need extra functionality, I think I have a solution for you.

I think the problem you're having is because the unconfigured GetEnumerator() on stringFake will always return a new enumerator (FakeItEasy will have unconfigured properties always return the same value, but unconfigured methods do not cache their return values and will give new values easy time).

If you configure it to return a particular enumerator, you should have better luck. I don't have a compiler with me, but something like:

IEnumarableString stringFake = A.Fake<IEnumarableString>();
IEnumerator<string> fakeEnumerator = A.Fake<IEnumerator<string>>();

A.CallTo(() => stringFake.GetEnumerator()).Returns(fakeEnumerator);
A.CallTo(() => fakeEnumerator.MoveNext()).ReturnsNextFromSequence(true, false);

Or something. Note that you'll also have to set up the behaviour on fakeEnumerator.Current. There is already a question that deal with faking an enumerator. You should be able to see it for additional details—Faking an enumerator in FakeItEasy

Community
  • 1
  • 1
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • Thanks, It looks promising, but I manage to make it work only if fakeEnumerator.MoveNext() is configured to return true first and then false, configuring Current does seems like a challenge, if it will work I will mark this as the answer – yshuki Dec 31 '13 at 09:02
  • Simply set up the `Current` to `ReturnsNextFromSequence` with the actual values that are expected. – Reyhn Apr 28 '20 at 06:44
0

it seems unnatural to be faking ones own objects, I typically fake only dependencies that I have no control over. In a situation like this, I would use a constructor that lets me pass in a ready made array of strings. Alternatively, I would make a different implementation of IEnumerableString with the test behaviour I wanted.

If AdvancedString is the unit under test, then simply give it some test data to work on, don't try to fake the enumerable, since that is part of what you are testing.

Tim Long
  • 13,508
  • 19
  • 79
  • 147