Как использовать Assert (или другой тестовый класс?), Чтобы убедиться, что выбрано исключение?Как использовать Assert для проверки того, что было выбрано исключение?
ответ
Для "Visual Team Team Test", похоже, вы применяете атрибут ExpectedException к методу теста.
Пример из документации здесь: A Unit Testing Walkthrough with Visual Studio Team Test
[TestMethod]
[ExpectedException(typeof(ArgumentException),
"A userId of null was inappropriately allowed.")]
public void NullUserIdInConstructor()
{
LogonInfo logonInfo = new LogonInfo(null, "[email protected]");
}
Атрибут ExpectedException выше работает и в NUnit (но [TestMethod] должен быть [Test]). – dbkk
@dbkk: Не работает точно так же в NUnit - сообщение обрабатывается как строка, которая должна отвечать на сообщение об ошибке (и я думаю, что это имеет смысл) –
Этот атрибут выполняет свою работу и является встроенной функцией для C#, но я не рекомендую использовать его, поскольку он недостаточно гибкий. Подумайте, что произойдет, если тип исключения будет указан вашим тестовым установочным кодом: test pass, но на самом деле не сделал то, что вы ожидали. Или что делать, если вы хотите проверить состояние объекта исключения. Обычно я хочу использовать StringAssert.Contains (e.Message ...), а не тестировать все сообщение. Используйте метод assert, как описано в других ответах. – steve
Обычно для этого в вашем испытательном каркасе будет ответ. Но если это не является достаточно гибкой, вы всегда можете сделать это:
try {
somethingThatShouldThrowAnException();
Assert.Fail(); // If it gets to this line, no exception was thrown
} catch (GoodException) { }
Как @Jonas указывает, это не работает для ловли базовый Exception:
try {
somethingThatShouldThrowAnException();
Assert.Fail(); // raises AssertionException
} catch (Exception) {
// Catches the assertion exception, and the test passes
}
Если вы абсолютно необходимо поймать исключение, вам нужно повторно сбросить Assert.Fail(). Но на самом деле, это знак, который вы не должны писать вручную; проверьте свою тестовую структуру для параметров или посмотрите, можете ли вы использовать более значимое исключение для тестирования.
Вы должны иметь возможность адаптировать этот подход к любым вашим потребностям - включая указание каких исключений для улова. Если вы только ожидать определенных типов, закончить catch
блоки прочь с:
} catch (GoodException) {
} catch (Exception) {
// not the right kind of exception
Assert.Fail();
}
+1, я использую этот путь вместо этого атрибута, когда мне нужно сделать утверждения, выходящие за пределы типа исключения. Например, что, если нужно проверить, что определенные поля в экземпляре исключения установлены на определенные значения. –
Мне это нравится, потому что вам не нужно указывать точное сообщение об ошибке, например, с помощью подхода атрибута – user12345613
У вас нет необходимости указывать сообщение об ошибке. Этого достаточно: [ExpectedException (typeof (ArgumentException))] – mibollma
Это атрибут метода испытания ... не использовать Assert. Нам кажется, что так:
[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()
Это будет зависеть от того, что тест рамки вы используете?
В MbUnit, например, вы можете указать ожидаемое исключение с атрибутом, чтобы убедиться, что вы получаете исключение, которое вы действительно ожидаете.
[ExpectedException(typeof(ArgumentException))]
Заканчивать nUnit Docs примеры о:
[ExpectedException(typeof(ArgumentException))]
Если вы используете MSTest, которые изначально не имеют атрибут ExpectedException
, вы можете сделать это:
try
{
SomeExceptionThrowingMethod()
Assert.Fail("no exception thrown");
}
catch (Exception ex)
{
Assert.IsTrue(ex is SpecificExceptionType);
}
Это действительно работает, но я не рекомендую это вообще, так как логика слишком сложна. Не сказать, что это запутанно, но подумайте, напишите ли вы этот блок кода для нескольких тестов - 10 с, 100 с тестов. Эта логика должна быть обработана до хорошо продуманного метода assert. См. Другие ответы. – steve
Будьте осторожны с использованием ExpectedException, так как это может привести к нескольким ошибкам, как показано здесь:
http://geekswithblogs.net/sdorman/archive/2009/01/17/unit-testing-and-expected-exceptions.aspx
И здесь:
http://xunit.github.io/docs/comparisons.html
Если вам необходимо проверить для исключения, есть менее неодобрительно способами. Вы можете использовать метод try {act/fail} catch {assert}, который может быть полезен для фреймворков, которые не имеют прямой поддержки для тестов исключений, отличных от ExpectedException.
Лучшей альтернативой является использование xUnit.NET, которая является очень современной, перспективной и расширяемой модульной схемой тестирования, которая узнала из всех других ошибок и улучшилась.Одним из таких улучшений является Assert.Throws, который обеспечивает гораздо лучший синтаксис для утверждения исключений.
Вы можете найти xUnit.NET на GitHub: http://xunit.github.io/
Обратите внимание, что теперь NUnit 2.5 также поддерживает синтаксис синтаксиса Assert.Throws - http://nunit.com/index.php?p=releaseNotes&r=2.5 – Alconja
То, как завершаются тесты устройства, чтобы вы знали об исключении при использовании ExpectedException сводит меня с ума. Почему MS подумала, что было бы неплохо иметь ручной шаг в автоматизированных тестах? Спасибо за ссылки. – Ant
@Ant: MS скопировал NUnit ... так что реальный вопрос: почему NUnit подумал, что это хорошая идея? – jrista
В виде i'm проекта работает на нас есть другое решение, делая это.
Сначала мне не нравится ExpectedExceptionAttribute, потому что он принимает во внимание, какой вызов метода вызвал Исключение.
Я делаю это вместо helpermethod.
Тест
[TestMethod]
public void AccountRepository_ThrowsExceptionIfFileisCorrupt()
{
var file = File.Create("Accounts.bin");
file.WriteByte(1);
file.Close();
IAccountRepository repo = new FileAccountRepository();
TestHelpers.AssertThrows<SerializationException>(()=>repo.GetAll());
}
HelperMethod
public static TException AssertThrows<TException>(Action action) where TException : Exception
{
try
{
action();
}
catch (TException ex)
{
return ex;
}
Assert.Fail("Expected exception was not thrown");
return null;
}
Аккуратные, не правда ли;)
Мой предпочтительный способ реализации этого заключается в написании метод, называемый броски, и использовать его точно так же, как и любой другой метод Assert. К сожалению, .NET не позволяет писать статический метод расширения, поэтому вы не можете использовать этот метод, как если бы он действительно принадлежал сборке в классе Assert; просто сделайте еще один вызов MyAssert или что-то подобное. Класс выглядит следующим образом:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace YourProject.Tests
{
public static class MyAssert
{
public static void Throws<T>(Action func) where T : Exception
{
var exceptionThrown = false;
try
{
func.Invoke();
}
catch (T)
{
exceptionThrown = true;
}
if (!exceptionThrown)
{
throw new AssertFailedException(
String.Format("An exception of type {0} was expected, but not thrown", typeof(T))
);
}
}
}
}
Это означает, что ваш блок тест выглядит следующим образом:
[TestMethod()]
public void ExceptionTest()
{
String testStr = null;
MyAssert.Throws<NullReferenceException>(() => testStr.ToUpper());
}
который выглядит и ведет себя гораздо больше похож на остальных модульных тестов синтаксисов.
, так что вам не нравятся атрибуты? –
Избавьтесь от флага bool и поместите бросок в строку непосредственно после вызова для более компактной реализации. –
Единственное, что делает это лучше, - это вернуть функцию исключенному исключению, чтобы вы могли продолжать утверждать, что такие вещи, как атрибуты исключения, верны. –
Ну я буду в значительной степени суммируют, что все остальные здесь уже говорил ... В любом случае, вот код я построен в соответствии с хорошими ответами :) Все, что осталось сделать, это скопировать и использовать ...
/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException.
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="methodToExecute">The method to execute to generate the exception.</param>
public static void AssertRaises<TException>(Action methodToExecute) where TException : System.Exception
{
try
{
methodToExecute();
}
catch (TException) {
return;
}
catch (System.Exception ex)
{
Assert.Fail("Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
Помощник, предоставляемый @Richiban выше, отлично работает, за исключением того, что он не обрабатывает ситуацию, когда генерируется исключение, но не ожидается тип. Следующие адреса, которые:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace YourProject.Tests
{
public static class MyAssert
{
/// <summary>
/// Helper for Asserting that a function throws an exception of a particular type.
/// </summary>
public static void Throws<T>(Action func) where T : Exception
{
Exception exceptionOther = null;
var exceptionThrown = false;
try
{
func.Invoke();
}
catch (T)
{
exceptionThrown = true;
}
catch (Exception e) {
exceptionOther = e;
}
if (!exceptionThrown)
{
if (exceptionOther != null) {
throw new AssertFailedException(
String.Format("An exception of type {0} was expected, but not thrown. Instead, an exception of type {1} was thrown.", typeof(T), exceptionOther.GetType()),
exceptionOther
);
}
throw new AssertFailedException(
String.Format("An exception of type {0} was expected, but no exception was thrown.", typeof(T))
);
}
}
}
}
Хммм ... Я понимаю идею, но я не уверен, что согласен, что это лучше. Просто потому, что мы хотим обеспечить конкретное исключение, это не означает, что все остальные должны быть обернуты как отказ от утверждения.IMHO неизвестное исключение должно просто пузырить стек, как это было бы в любой другой операции подтверждения. – Crono
@Martin Я удаляю код с участием exceptionOther и просто удаляю из второго предложения catch –
если вы используете NUnit, вы можете сделать что-то вроде этого:
Assert.Throws<ExpectedException>(() => methodToTest());
Также можно хранить выброшенное исключение для того, чтобы проверить его дальше:
ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest());
Assert.AreEqual("Expected message text.", ex.Message);
Assert.AreEqual(5, ex.SomeNumber);
Это также работает с MSTest. –
Я не рекомендую использовать атрибут 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)
}
ПРИМЕЧАНИЯ
Возвращаясь исключение вместо поддержки обратного вызова проверки является разумной идеей исключением того, что делать это делает вызывающий синтаксис этого утверждают очень отличается от других утверждает, что я использую.
В отличие от других, я использую 'распространение' вместо 'throws', так как мы можем только проверить, распространяется ли исключение из вызова. Мы не можем напрямую проверить, что выбрано исключение. Но я полагаю, что вы могли бы изобразить броски: бросить и не поймать.
FINAL МЫСЛЬ
Прежде чем перейти к такому роду подход я считал с помощью атрибута ExpectedException, когда тест только проверить тип исключения и использование попытки/поймать блок, если требуется более проверка. Но не только я должен был подумать о том, какой метод использовать для каждого теста, но изменение кода от одного метода к другому по мере изменения потребностей было не тривиальным усилием. Использование одного последовательного подхода позволяет сэкономить умственные усилия.
Таким образом, этот подход спортивный: простота в использовании, гибкость и надежность (трудно сделать это неправильно).
Вы можете скачать пакет с NuGet помощью: PM> Install-Package MSTestExtensions, который добавляет Assert.Throws() синтаксис в стиле NUnit/XUnit к MSTest.
инструкции высокого уровня: скачать сборку и наследовать от BaseTest и вы можете использовать Assert.Throws() синтаксиса.
Основной метод для Выдает реализации выглядит следующим образом:
public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
{
try
{
task();
}
catch (Exception ex)
{
AssertExceptionType<T>(ex);
AssertExceptionMessage(ex, expectedMessage, options);
return;
}
if (typeof(T).Equals(new Exception().GetType()))
{
Assert.Fail("Expected exception but no exception was thrown.");
}
else
{
Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
}
}
Раскрытие информации: я соединял этот пакет.
Дополнительная информация: http://www.bradoncode.com/blog/2012/01/asserting-exceptions-in-mstest-with.html
Спасибо за пример. Есть ли у вас пример тестирования Assert.DoesNotThrow() или эквивалента? –
Несмотря на то, что это старый вопрос, я хотел бы добавить новую мысль к обсуждению. Я продлил шаблон Arrange, Act, Assert, который должен быть ожидаемым, упорядочить, действовать, утверждать. Вы можете сделать ожидаемый указатель исключения, а затем утверждать, что ему присвоен. Это кажется более чистым, чем выполнение ваших утверждений в блоке catch, оставляя ваш раздел Act главным образом только для одной строки кода для вызова тестируемого метода. У вас также не должно быть Assert.Fail();
или return
с нескольких точек в коде. Любое другое вызванное исключение приведет к сбою теста, потому что оно не будет поймано, и если выбрано исключение из вашего ожидаемого типа, но это не тот, который вы ожидали, утверждение против сообщения или других свойств исключение поможет убедиться, что ваш тест не пройдет непреднамеренно.
[TestMethod]
public void Bar_InvalidDependency_ThrowsInvalidOperationException()
{
// Expectations
InvalidOperationException expectedException = null;
string expectedExceptionMessage = "Bar did something invalid.";
// Arrange
IDependency dependency = DependencyMocks.Create();
Foo foo = new Foo(dependency);
// Act
try
{
foo.Bar();
}
catch (InvalidOperationException ex)
{
expectedException = ex;
}
// Assert
Assert.IsNotNull(expectedException);
Assert.AreEqual(expectedExceptionMessage, expectedException.Message);
}
Поскольку вы упоминаете с помощью других тестовых классов, лучший вариант, чем атрибут ExpectedException
является использование Shoudly «s Should.Throw.
Should.Throw<DivideByZeroException>(() => { MyDivideMethod(1, 0); });
Допустим, у нас есть требование, чтобы клиент должен иметь адрес для создания заказа. Если нет, метод CreateOrderForCustomer
должен привести к ArgumentException
. Тогда мы могли бы написать:
[TestMethod]
public void NullUserIdInConstructor()
{
var customer = new Customer(name := "Justin", address := null};
Should.Throw<ArgumentException>(() => {
var order = CreateOrderForCustomer(customer) });
}
Это лучше, чем при использовании атрибута ExpectedException
, потому что мы специфичны о том, что следует бросить эту ошибку. Это делает требования в наших тестах более ясными, а также облегчает диагностику при неудачном тестировании.
Примечание. Для асинхронного тестирования метода также есть Should.ThrowAsync
.
MSTest теперь имеет функцию Assert.ThrowsException, которая может быть использована, как это:
Assert.ThrowsException<System.FormatException>(() =>
{
Story actual = PersonalSite.Services.Content.ExtractHeader(String.Empty);
});
В качестве альтернативы вы можете попробовать исключения тестирования на самом деле бросают со следующими 2 линии в тесте.
var testDelegate =() => MyService.Method(params);
Assert.Throws<Exception>(testDelegate);
В случае использования NUnit, попробуйте следующее:
Assert.That(() =>
{
Your_Method_To_Test();
}, Throws.TypeOf<Your_Specific_Exception>().With.Message.EqualTo("Your_Specific_Message"));
В VS встроенный блок тестирования, если вы просто хотите, чтобы убедиться, что «любое исключение» отбрасывается, но вы не» t знать тип, вы можете использовать улов все:
[TestMethod]
[ExpectedException(typeof(Exception), AllowDerivedTypes = true)]
public void ThrowExceptionTest()
{
//...
}
- 1. Функция подтверждения на C++ для проверки того, что исключение выбрано
- 2. Использовать Mockito для проверки того, что супер не было вызвано
- 3. Исключение типа Microsoft.WindowsAzure.StorageClient.StorageClientException было выбрано
- 4. Исключение было выбрано расписанием задач
- 5. Исключение типа 'Microsoft.Online.Administration.Automation.MicrosoftOnlineException' было выбрано
- 6. Как использовать assert для проверки строки
- 7. Исключение было выбрано целью вызова
- 8. Исключение типа 'System.OutOfMemoryException' было выбрано.
- 9. Исключение было выбрано мишенью для вызова # 2
- 10. Исключение типа 'System.OutOfMemoryException' было выбрано?
- 11. Исключение типа 'uPLibrary.Networking.M2Mqtt.Exceptions.MqttClientException' было выбрано
- 12. Как утверждать, что исключение не было поднято?
- 13. Как проверить, что конкретное исключение выбрано в node.js и нажмите
- 14. AD GroupPrincipal: Исключение было выбрано мишенью вызова
- 15. spring mvc: обнаруживает, что при загрузке контекста было выбрано исключение
- 16. webclient Исключение было выбрано целью вызова
- 17. Ошибка конфигурации - Исключение было выбрано целью вызова
- 18. Django представляет форму действия на основе того, что было выбрано
- 19. Обнаружение того, что было выбрано на Listbox DataTemplate
- 20. Написание единицы измерения для проверки того, что событие было инициировано
- 21. 400 - Исключение типа «DotNetNuke.Services.Exceptions.SecurityException» было выбрано
- 22. VB.Net Исключение было выбрано целью вызова
- 23. Sys.WebForms.PageRequestManagerServerErrorException: Исключение было выбрано целевым объектом вызова
- 24. Ошибка: исключение было выбрано целью вызова. Параметры
- 25. Исключение было выбрано целью вызова (MethodBase.Invoke Method)
- 26. Исключение было выбрано целью вызова в C#
- 27. Исключение Kinect было выбрано целью вызова
- 28. Ошибка: «Исключение было выбрано целью вызова».
- 29. Исключение было выбрано целью вызова в VS2013
- 30. ошибка datagrid: Исключение было выбрано целью вызова
Какую модульную систему тестирования вы используете? –
Visual Studio Integrated – Alex
Не используется атрибут ExpectedException? ref: http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.expectedexceptionattribute.aspx – shahkalpesh