Я не рекомендую использовать атрибут ExpectedException (поскольку он слишком ограничен и подвержен ошибкам) или записывать блок try / catch в каждом тесте (поскольку он слишком сложен и подвержен ошибкам). Используйте хорошо разработанный метод assert - либо предоставленный вашей тестовой средой, либо напишите свой собственный. Вот что я написал и использую.
public static class ExceptionAssert
{
private static T GetException<T>(Action action, string message="") where T : Exception
{
try
{
action();
}
catch (T exception)
{
return exception;
}
throw new AssertFailedException("Expected exception " + typeof(T).FullName + ", but none was propagated. " + message);
}
public static void Propagates<T>(Action action) where T : Exception
{
Propagates<T>(action, "");
}
public static void Propagates<T>(Action action, string message) where T : Exception
{
GetException<T>(action, message);
}
public static void Propagates<T>(Action action, Action<T> validation) where T : Exception
{
Propagates(action, validation, "");
}
public static void Propagates<T>(Action action, Action<T> validation, string message) where T : Exception
{
validation(GetException<T>(action, message));
}
}
Пример использования:
[TestMethod]
public void Run_PropagatesWin32Exception_ForInvalidExeFile()
{
(test setup that might propagate Win32Exception)
ExceptionAssert.Propagates<Win32Exception>(
() => CommandExecutionUtil.Run(Assembly.GetExecutingAssembly().Location, new string[0]));
(more asserts or something)
}
[TestMethod]
public void Run_PropagatesFileNotFoundException_ForExecutableNotFound()
{
(test setup that might propagate FileNotFoundException)
ExceptionAssert.Propagates<FileNotFoundException>(
() => CommandExecutionUtil.Run("NotThere.exe", new string[0]),
e => StringAssert.Contains(e.Message, "NotThere.exe"));
(more asserts or something)
}
ПРИМЕЧАНИЯ
Возвращение исключения вместо поддержки обратного вызова проверки является разумной идеей, за исключением того, что при этом синтаксис вызова этого утверждения сильно отличается от других утверждений, которые я использую.
В отличие от других, я использую «распространения» вместо «бросков», поскольку мы можем только проверить, распространяется ли исключение из вызова. Мы не можем напрямую проверить, что выброшено исключение. Но я полагаю, вы могли бы бросать изображения, чтобы означать: брошенный и не пойман.
ЗАКЛЮЧИТЕЛЬНАЯ МЫСЛЬ
Прежде чем перейти к такому подходу, я рассмотрел использование атрибута ExpectedException, когда тест проверял только тип исключения, и использование блока try / catch, если требовалась дополнительная проверка. Но я не только должен был думать о том, какую технику использовать для каждого теста, но и менять код с одной методики на другую по мере изменения потребностей не было тривиальной задачей. Использование одного последовательного подхода экономит умственные усилия.
Итак, в общем, этот подход к спорту: простота использования, гибкость и надежность (трудно сделать это неправильно).