Исключение, не выброшенное издевательством над объектом

Цель состоит в том, чтобы провести модульное тестирование метода PUBLIC VOID.

У меня есть издевательская служба, которую вызовет мой тестируемый класс, в цикле for-each с тремя разными параметрами.

Тестируемый класс передает некоторые входные параметры методу SendRequest службы, который выполняется с использованием этих параметров.

Я хочу, чтобы издевательская служба выдавала исключение, когда один из параметров имеет определенное значение, например «abc». Я использую что-то вроде этого:

   public class ClassUnderTest
   {
       private IMyService _myservice;
       public ClassUnderTest(IMyService myservice)
       {
           _myservice = myservice;
       }
       public void MyMethod()
       {
           //assume I get those 3 values from somewhere, in here.
           var list = new List<string>{"abc","aaa","bbb"};
           foreach(var item in list)
               {
                   try
                   {
                       _myservice.SendRequest(item);
                   }
                   catch(Exception ex)
                   {
                       //do some logging and continue calling service with next item in list
                   }
              }
       }
   }

        var myService = new Mock<IMyService>();
        myService.Setup(x => x.SendRequest("abc")).Throws<Exception>();
        myService.Setup(x => x.SendRequest("aaa"));
        myService.Setup(x => x.SendRequest("bbb"));

        var classUnderTest = new ClassUnderTest(myService.Object);
        classUnderTest.MyMethod();
        myService.Verify(x =>x.SendRequest(It.IsAny<string>()), Times.Exactly(2));

Дополнительный контекст: поскольку MyMethod возвращает void, для его проверки я могу полагаться только на тот факт, что мои зависимости вызывались в разных частях кода в этом методе. Например, если перед вызовом службы выполняется проверка на нулевое значение для входных параметров, метод вернется до того, как вызовет службу. Если он пройдет нулевую проверку, будет вызвана служба зависимостей. Я мог бы отслеживать их в результатах покрытия кода (и в режиме отладки).

Когда я запускаю тест, он терпит неудачу, потому что он вызывает службу трижды, но я ожидаю, что вызов произойдет дважды (теперь, возможно, я ошибаюсь, и может быть так, что, хотя предполагается, что он должен вызывать исключение, попытка вызова все еще подсчитывается вызовом Verify и следовательно, я получаю 3 пробега).

Как бы то ни было, при отладке я вижу, что служба никогда не выдает исключение. У меня есть try-catch в цикле for-each, где я хочу вести журнал и продолжать снова вызывать службу со следующим значением. Но я никогда не попаду внутрь блока Catch.

Что я делаю неправильно?


person Abhishek Tiwari    schedule 08.10.2015    source источник
comment
Вам нужно показать свой фактический код   -  person stuartd    schedule 08.10.2015
comment
Как убедиться, что classUnderTest.MyMethod() вызовет myService.SendRequest() с помощью abc? Вы отлаживали и видели?   -  person Arghya C    schedule 08.10.2015
comment
Вы уверены, что пойман правильный тип исключения?   -  person Maor Veitsman    schedule 08.10.2015
comment
Ну, конечно, проверка не удалась - вы вызываете этот метод 3 раза! Проверка вызова метода не заботится о результате метода. Вам нужно будет проверить некоторые другие измерения.   -  person Owen Pauling    schedule 08.10.2015
comment
Возможный дубликат MOQ - проверка исключения   -  person Owen Pauling    schedule 08.10.2015
comment
[1] Даже если выброшено исключение, SendRequest будет вызываться трижды. [2] И исключение, выброшенное MyService, здесь не имеет значения, потому что ваше MyMethod обрабатывает его. Однако необработанные исключения ведут себя по-разному в модульных тестах.   -  person Arghya C    schedule 08.10.2015
comment
Мне нужно иметь возможность протестировать блок Catch MyMethod, где у меня будет дополнительный код для выполнения некоторых действий. Assert.Throws‹Exception›() просто утверждает, вызовет ли этот делегат указанное исключение. Не то, что мне нужно. Мне нужно, чтобы исключение вызывалось, когда модульный тест вызывает службу, чтобы он также вошел в блок Catch моего метода.   -  person Abhishek Tiwari    schedule 08.10.2015
comment
@OwenPauling Да, я думаю, количество вызовов все равно будет 3.   -  person Abhishek Tiwari    schedule 08.10.2015
comment
Он вызывает его три раза. Один из раз выдает исключение.   -  person    schedule 08.10.2015


Ответы (1)


Вариант 1: Конкретное исключение
Мое 1-е предложение будет вызывать более конкретное исключение, чтобы вы могли быть более уверены.

Вариант 2. Внедрить службу ILogger
Рефакторинг ведения журнала в ILogger и внедрить его. Затем передайте макет этого и заявите против него.

Вариант 3: Извлечение и переопределение
Если вы должны проверить, что блок catch попал, вы можете использовать извлечение и переопределение:

public class ClassUnderTest
{
    private IMyService _myservice;
    public ClassUnderTest(IMyService myservice)
    {
        _myservice = myservice;
    }
    public void MyMethod()
    {
        //assume I get those 3 values from somewhere, in here.
        var list = new List<string>{"abc","aaa","bbb"};
        foreach(var item in list)
            {
                try
                {
                    _myservice.SendRequest(item);
                }
                catch(Exception ex)
                {
                    LogError(ex);
                }
            }
    }

    protected virtual LogException(Exception ex)
    {
        //do logging
    }
}

public class TestableClassUnderTest : ClassUnderTest
{
    public bool LoggingWasCalled { get; set; }

    protected virtual LogException(Exception ex)
    {
        LoggingWasCalled = true;
    }
}

Тогда вы могли бы проверить что-то вроде этого:

var testableSut = new TestableClassUnderTest ();
testableSut.MyMethod("abc");
Assert.True(testableSut.LoggingWasCalled);

Более подробно я расскажу об этом здесь: http://devonburriss.me/testing-the-untestable/< /а>

person Devon Burriss    schedule 08.10.2015