Как я могу проверить ожидаемое исключение с конкретным сообщением об исключении из файла ресурсов в Visual Studio Test?
Тест Visual Studio может проверять ожидаемые исключения, используя атрибут ExpectedException. Вы можете передать исключение, подобное этому:
[TestMethod]
[ExpectedException(typeof(CriticalException))]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
Вы также можете проверить сообщение, содержащееся в ExpectedException, следующим образом:
[TestMethod]
[ExpectedException(typeof(CriticalException), "An error occured")]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
Но при тестировании I18N-приложений я бы использовал файл ресурсов для получения этого сообщения об ошибке (любой может даже решить протестировать различные локализации сообщения об ошибке, если захочу, но Visual Studio не позволит мне сделать это:
[TestMethod]
[ExpectedException(typeof(CriticalException), MyRes.MultipleOrganisationsNotAllowed)]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
Компилятор выдаст следующую ошибку:
Аргумент атрибута должен быть постоянное выражение, выражение typeof или выражение создания массива Атрибут
Кто-нибудь знает, как тестировать исключение, имеющее сообщение из файла ресурсов?
Один из вариантов, который я рассмотрел, - это использование настраиваемых классов исключений, но на основе часто слышимых советов, таких как:
"Создавать и создавать пользовательские исключения если у вас есть условие ошибки, могут быть программно обработаны в иначе, чем любые другие существующие исключение. В противном случае бросьте один из существующие исключения." Источник
Я не собираюсь обрабатывать исключения по-разному в обычном потоке (это критическое исключение, поэтому я все равно попаду в панический режим), и я не думаю, что создание исключения для каждого тестового примера - это правильная вещь для делать. Любые мнения?
Ответы
Ответ 1
Просто мнение, но я бы сказал текст ошибки:
- является частью теста, и в этом случае получение его из ресурса будет "неправильным" (в противном случае вы могли бы получить скомпонованный ресурс), так что просто обновите тест, когда вы измените ресурс (или тест не сработает) )
- не является частью теста, и вы должны только заботиться о том, чтобы он выдавал исключение.
Обратите внимание, что первый вариант должен позволить вам протестировать несколько языков, учитывая возможность запуска с локали.
Как и для нескольких исключений, я из земли С++, где создание нагрузок и множеств исключений (до одного выражения "за один"!) в больших искажениях приемлемо (если не общее), но .Net-метаданные системе, вероятно, это не нравится, следовательно, этот совет.
Ответ 2
Я бы рекомендовал использовать вспомогательный метод вместо атрибута. Что-то вроде этого:
public static class ExceptionAssert
{
public static T Throws<T>(Action action) where T : Exception
{
try
{
action();
}
catch (T ex)
{
return ex;
}
Assert.Fail("Exception of type {0} should be thrown.", typeof(T));
// The compiler doesn't know that Assert.Fail
// will always throw an exception
return null;
}
}
Затем вы можете написать свой тест примерно так:
[TestMethod]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
{
OrganizationList organizations = new Organizations();
organizations.Add(new Organization());
organizations.Add(new Organization());
var ex = ExceptionAssert.Throws<CriticalException>(
() => organizations.GetOrganization());
Assert.AreEqual(MyRes.MultipleOrganisationsNotAllowed, ex.Message);
}
Это также имеет то преимущество, что он проверяет, что исключение выбрасывается на строку, которую вы ожидали, чтобы она была выбрана, а не где-либо в вашем тестовом методе.
Ответ 3
Аргумент ExpectedException Message не совпадает с сообщением об исключении. Скорее это сообщение, которое печатается в результатах теста, если ожидаемое исключение фактически не произошло.
Ответ 4
Я думаю, вы можете просто сделать явный try-catch в своем тестовом коде вместо того, чтобы полагаться на атрибут ExpectedException, чтобы сделать это за вас. Затем вы можете найти какой-нибудь вспомогательный метод, который будет читать файл ресурсов и сравнить сообщение об ошибке с тем, которое приходит с исключением, которое было обнаружено. (конечно, если не было исключения, тогда тестовый случай следует считать неудачным)
Ответ 5
Если вы переключитесь на использование очень приятной xUnit.Net тестовой библиотеки, вы можете заменить [ExpectedException] на что-то вроде этого:
[Fact]
public void TestException()
{
Exception ex = Record.Exception(() => myClass.DoSomethingExceptional());
// Assert whatever you like about the exception here.
}
Ответ 6
Интересно, движется ли NUnit по пути от простоты... но здесь вы идете.
Новые улучшения (2.4.3 и выше?) к атрибуту ExpectedException позволяют вам больше контролировать проверки, которые должны выполняться в ожидаемом исключении с помощью метода Handler. Подробнее о официальной странице документа NUnit.. в конце страницы.
[ExpectedException( Handler="HandlerMethod" )]
public void TestMethod()
{
...
}
public void HandlerMethod( System.Exception ex )
{
...
}
Примечание. Что-то здесь не так хорошо. Почему ваши сообщения об исключениях интернационализированы. Используете ли вы исключения для вещей, которые необходимо обработать или уведомить пользователя. Если у вас нет кучки разработчиков разных культур, которые бы исправляли ошибки, вам не нужно это делать. Исключений на английском языке или общепринятого языка было бы достаточно. Но в случае, если вы должны иметь это.. его возможно:)
Ответ 7
Я столкнулся с этим вопросом, пытаясь решить подобную проблему самостоятельно. (Я подробно рассмотрю решение, о котором я остановился ниже.)
Я должен согласиться с комментариями Gishu о интернационализации сообщений об исключениях, являющихся запахами кода.
Я сделал это изначально в своем собственном проекте, чтобы у меня была согласованность между сообщениями об ошибках, передаваемыми моим приложением и в моих модульных тестах. т.е. только для того, чтобы определять мои сообщения об исключениях в одном месте и в то время, файл ресурсов казался разумным местом для этого, поскольку я уже использовал его для различных меток и строк (и поскольку имеет смысл добавить ссылку к нему в моем тестовом коде, чтобы убедиться, что те же метки указаны в соответствующих местах).
В какой-то момент я рассмотрел (и протестировал) использование блоков try/catch, чтобы избежать требования константы по атрибуту ExpectedException, но это казалось, что это привело бы к довольно большому количеству дополнительного кода, если бы оно применялось в больших масштабах.
В конце концов, решение, на котором я остановился, состояло в том, чтобы создать статический класс в моей библиотеке ресурсов и сохранить в нем мои сообщения об исключениях. Таким образом, нет необходимости интернационализировать их (что я соглашусь не имеет смысла), и они становятся доступными в любое время, когда строка ресурсов будет доступна, поскольку они находятся в одном пространстве имен. (Это соответствует моему желанию не проверять текст исключения сложным процессом.)
Мой тестовый код затем просто сводится к (помилование mangling...):
[Test,
ExpectedException(typeof(System.ArgumentException),
ExpectedException=ProductExceptionMessages.DuplicateProductName)]
public void TestCreateDuplicateProduct()
{
_repository.CreateProduct("TestCreateDuplicateProduct");
_repository.CreateProduct("TestCreateDuplicateProduct");
}