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

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

так что мой тест выглядит так

[TestMethod]
[ExpectedException(typeof(IOException))]
public void RecordAnalyser_FileReadFailedInFirstAttempt_WarningLogged()
{
    //Arrange
    var fileMock = Substitute.For<IFile>();
    fileMock.ReadLines(Arg.Any<string>()).Throws(new IOException());

    //Act
    var recordAnalyser = new RecordAnalyser(fileMock, logger); //--> throws exception.

    //Assert
    logger.Received(1).Warn(Arg.Any<string>(), Arg.Any<Exception>());
}

Теперь я хочу утверждать, что регистратор получил журнал предупреждений, но так как строка выше отправляет исключение, и у меня есть атрибут ожидаемого исключения, test не проверяет утверждение.

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

//Act
try
{
    var recordAnalyser = new RecordAnalyser(fileMock, logger);
}
catch (Exception)
{
    // eat
}

Тестируемый код -

public RecordAnalyser(IFile file, ILoggerService logger)
{
    this.logger = logger;
    try
    {
        names = file.ReadLines(Constants.Names).ToList();
    }
    catch (System.IO.IOException e)
    {
        logger.Error("Names file could not be read.", ex);
      // How do I test above line without a try catch block in unit test 
        throw;
    } 
}

ищу предложения здесь.

2 ответа

Это может быть проблемой XY.

Вы пытаетесь проверить / утвердить несколько вещей в одном тесте. отсюда и проблема.

Если бы цель состояла в том, чтобы просто проверить, что выбрасывается исключение, то не было бы никаких попыток try/catch и test.

[TestMethod]
[ExpectedException(typeof(IOException))]
public void RecordAnalyser_Should_FailInFirstAttempt_When_FileRead() {
    //Arrange
    var fileMock = Substitute.For<IFile>();
    fileMock.ReadLines(Arg.Any<string>()).Throws(new IOException());

    //Act
    var recordAnalyser = new RecordAnalyser(fileMock, logger); //--> throws exception.
}

В другом тесте, где вы хотите утверждать, что что-то происходит, когда выдается исключение, вам нужно будет перехватить исключение, чтобы позволить завершить тест и позволить проверке утверждений.

[TestMethod]
public void RecordAnalyser_Should_LogWarning_When_FileReadFailedInFirstAttempt() {
    //Arrange
    var fileMock = Substitute.For<IFile>();
    fileMock.ReadLines(Arg.Any<string>()).Throws(new IOException());
    IOException error = null;

    //Act
    try {
        var recordAnalyser = new RecordAnalyser(fileMock, logger); //--> throws exception.
    } catch(IOException ex) {
        error = ex; //catch and hold error for later
    }

    //Assert

    if(error == null)
        Assert.Failed("exception expected"); // error was not thrown.

    logger.Received(1).Warn(Arg.Any<string>(), Arg.Any<Exception>());
}    

Вы можете использовать следующее расширение, которое обеспечивает реализацию Assert.Throws(Action) и Assert.Throws(Action): https://github.com/bbraithwaite/MSTestExtensions

Другие вопросы по тегам