Как выполнить модульное тестирование для принятого вызова в методе, который вызывает исключение
Я пытаюсь выполнить модульное тестирование метода, который выдает исключение, и перед тем, как его сгенерировать, необходимо выполнить несколько задач, таких как ведение журнала. я использую 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