How to make a FakeItEasy faked object's method throw on first invocation and return on second?

StackOverflow https://stackoverflow.com/questions/19731003

سؤال

I have a method which is invoked multiple times within a foreach loop, each time with the same parameter values.

foreach (var item in myCollection)
{
    // do some stuff with item
    // then...
    var result = _myService.Foo(aConstant, anotherConstant);
    // do something with result
}

I am trying to write a test that ensures the loop continues iterating even if _myService.Foo() throws an exception on the first time through.

In Moq, I am allowed to chain together calls to Returns and Throws like so:

mockService.Setup(x => x.Foo(aConstant, anotherConstant)).Throws<Exception>().Returns(someResult);

This will cause the call to Foo to throw an Exception but all subsequent calls will return someResult. My main goal is to ensure that a try/catch block is wrapped around the second half of code inside my foreach block so that the loop continues even if an Exception occurs.

foreach (var item in myCollection)
{
    // do some stuff with item
    // then...
    try
    {
        var result = _myService.Foo(aConstant, anotherConstant);
        // do something with result
    }
    catch (Exception e)
    {
        // ignore any exceptions here and continue looping
    }
}

How can I accomplish something similar to this in FakeItEasy? Or is there a different (better) strategy I could use for doing this kind of assertion?

هل كانت مفيدة؟

المحلول

You can now chain configurations using 'Then'. You can read more about it in the FakeItEasy documentation for changing behavior between calls.

This is an example:

public interface IFoo
{
    int Do();
}

[Test]
public void ThrowsFirstTime()
{
    var fakeFoo = A.Fake<IFoo>();
    A.CallTo(() => fakeFoo.Do()).Throws<Exception>().Once().Then.Returns(1);

    Assert.Throws<Exception>(()=>fakeFoo.Do());
    int t = fakeFoo.Do();

    A.CallTo(() => fakeFoo.Do()).MustHaveHappened(Repeated.Exactly.Twice);
    Assert.That(t, Is.EqualTo(1));
}

نصائح أخرى

In case it helps anyone else…

I figured out a way to do this for methods with void return type. I used the Invokes() method:

A.CallTo(() => _fakeService.VoidMethod(aConstant, anotherConstant))
                           .Invokes(ThrowExceptionOnFirstInvocation);

Then outside the Test method, I defined the ThrowExceptionOnFirstInvocation function:

private void ThrowExceptionOnFirstInvocation(IFakeObjectCall obj)
{
    if (_numInvocations++ == 0) throw new Exception();
}

private int _numInvocations;

I am still not sure how to do this for a method which returns something though.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top