Подтвердить что ты не робот

Moq: Настройте посмеянный метод сбой при первом вызове, преуспеть на втором

Какой самый лаконичный способ использовать Moq для издевательства над методом, который будет генерировать исключение при первом вызове, а затем выполнить второй раз, когда он вызывается?

4b9b3361

Ответ 1

Я бы использовал Callback и увеличил счетчик, чтобы определить, нужно ли исключать исключение из Callback.

[Test]
public void TestMe()
{
    var count = 0;
    var mock = new Mock<IMyClass>();
    mock.Setup(a => a.MyMethod()).Callback(() =>
        {
            count++;
            if(count == 1)
                throw new ApplicationException();
        });
    Assert.Throws(typeof(ApplicationException), () => mock.Object.MyMethod());
    Assert.DoesNotThrow(() => mock.Object.MyMethod());
}

public interface IMyClass
{
    void MyMethod();
}

Ответ 2

Лучшее, что я придумал до сих пор, это:

interface IFoo
{
    void Bar();
}

[Test]
public void TestBarExceptionThenSuccess()
{
    var repository = new MockRepository(MockBehavior.Default);
    var mock = repository.Create<IFoo>();

    mock.Setup(m => m.Bar()).
        Callback(() => mock.Setup(m => m.Bar())). // Setup() replaces the initial one
        Throws<Exception>();                      // throw an exception the first time

    ...
}

Ответ 3

Фил Хаак имеет интересное сообщение о настройке метода для возврата определенной последовательности результатов. Похоже, что это была бы хорошая отправная точка с некоторой работой, потому что вместо последовательности значений определенного типа вам нужно было бы иметь последовательность результатов, которые могут иметь тип T или исключение.

Ответ 4

Начиная с Moq 4.2 вы можете просто использовать встроенный метод SetupSequence() (как указано комментарием @RichardBarnett).

Пример:

var mock = new Mock<IMyClass>();
mock.SetupSequence(x => x.MyMethod("param1"))
    .Throws<MyException>()
    .Returns("test return");