38

Visual Studio Test может проверять ожидаемые исключения с использованием атрибута ExpectedException. Вы можете передать в виде исключения, как это:Как я могу проверить ожидаемое исключение с конкретным сообщением об исключении из файла ресурсов в Visual Studio Test?

[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() 

compil er сообщит следующую ошибку:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute

Кто-нибудь знает, как протестировать исключение, содержащее сообщение из файла ресурсов?


Один из вариантов я рассматривал это с помощью пользовательских классов исключений, но на основе часто слышал советы, такие как:

"Do create and throw custom exceptions if you have an error condition that can be programmatically handled in a different way than any other existing exception. Otherwise, throw one of the existing exceptions." Source

Я не ожидал, чтобы обрабатывать исключения по-разному в нормальном потоке (это критическое исключение, поэтому я все равно попаду в панический режим), и я не думаю, что создание исключения для каждого тестового примера - это правильная вещь. Любые мнения?

+3

Параметр сообщение не get проверяется на сообщение об исключении. – 2009-10-08 16:55:21

ответ

7

Просто мнение, но я бы сказал, текст ошибки:

  • является частью теста, в этом случае получить его из ресурса будет «неправильно» (в противном случае вы могли бы в конечном итоге с последовательно управляемый ресурс), поэтому просто обновите тест при изменении ресурса (или сбой теста)
  • не является частью теста, и вам остается только заботиться о том, чтобы он выдавал исключение.

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

Что касается нескольких исключений, я из земли C++, где создание нагрузок и множеств исключений (до одного выражения «за каждый») в больших хирахимах приемлемо (если не распространено), но .Net системе метаданных, вероятно, это не нравится, следовательно, этот совет.

+0

Я бы выполнил простой proc, который читает файл ресурсов и находит сообщение для записи, ваш метод - отличный способ де-карты и потерять ценное время для обновления тестов (чего мы больше всего избегаем) – 2012-04-25 08:31:00

+0

@ Микки: Ну то вам повезло: другой ответ - это то, что вы ищете! Если вы * специально * хотите ** unit ** - проверьте, что он получает одно и то же сообщение, это нормально, но я предпочитаю, чтобы он получал сообщение * right *. Но если ваш проект отличается, тогда вы можете легко получить другой «правильный» ответ! – 2012-04-25 22:54:40

+0

Я не следую, используя тестирование DataBound Unit, вы можете сохранить свой торт и съесть его тоже. сопоставить ресурсы в привязке данных и отобразить культуру сообщений в тесте или наоборот. нет? – 2012-04-29 14:34:45

4

Я думаю, что вы можете просто сделать явный try-catch в своем тестовом коде вместо того, чтобы полагаться на атрибут ExpectedException, чтобы сделать это за вас. Затем вы можете найти какой-нибудь вспомогательный метод, который будет читать файл ресурсов и сравнить сообщение об ошибке с тем, которое приходит с исключением, которое было обнаружено. (Если, конечно, не был исключением, то тест следует рассматривать как неудачу)

3

При переключении с использованием очень хорошая библиотека xUnit.Net тестирования, вы можете заменить [ExpectedException] с чем-то вроде этого:

[Fact] 
public void TestException() 
{ 
    Exception ex = Record.Exception(() => myClass.DoSomethingExceptional()); 
    // Assert whatever you like about the exception here. 
} 
1

Интересно, движется ли NUnit по пути от простоты ... но здесь вы идете.

Новые усовершенствования (2.4.3 и выше?) К атрибуту ExpectedException позволяют вам больше контролировать выполнение проверок на ожидаемом исключении с помощью метода Handler. Подробнее о official NUnit doc page .. в конце страницы.

[ExpectedException(Handler="HandlerMethod")] 
public void TestMethod() 
{ 
... 
} 

public void HandlerMethod(System.Exception ex) 
{ 
... 
} 

Примечание: Что-то не чувствует себя хорошо здесь .. Почему ваши исключения сообщения МНОГОЯЗЫЧНОЕ .. Вы используете исключения для вещей, которые должны быть обработаны или уведомлением пользователя. Если у вас нет кучки разработчиков разных культур, которые бы исправляли ошибки, вам не нужно это делать. Исключений на английском языке или общепринятого языка было бы достаточно. Но в случае, если у вас это должно быть ... возможно.

63

Я бы рекомендовал использовать вспомогательный метод вместо атрибута. Что-то вроде этого:

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); 
} 

Это также имеет то преимущество, что она проверяет, что исключение на линии, которую вы ожидали, что это будет выбрасывается вместо любого способа тестирования.

13

Аргумент ExpectedException Message не совпадает с сообщением об исключении. Скорее это сообщение, которое печатается в результатах теста, если ожидаемое исключение на самом деле не произошло.

0

Я столкнулся с этим вопросом, пытаясь решить подобную проблему самостоятельно. (Я подробно рассмотрю решение, которое я установил ниже.)

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

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

В какой-то момент я рассмотрел (и протестировал) использование блоков try/catch, чтобы избежать требования константы по атрибуту ExpectedException, но это казалось бы, что это приведет к довольно большому количеству дополнительного кода, если применить его к большому масштаб.

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

Мой тестовый код, то просто сводится к (простите за коверкая ...):

[Test, 
    ExpectedException(typeof(System.ArgumentException), 
    ExpectedException=ProductExceptionMessages.DuplicateProductName)] 
public void TestCreateDuplicateProduct() 
{ 
    _repository.CreateProduct("TestCreateDuplicateProduct"); 
    _repository.CreateProduct("TestCreateDuplicateProduct"); 
} 
Смежные вопросы