Pregunta

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?

¿Fue útil?

Solución

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));
}

Otros consejos

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top