На эти ответы: как насчет многократных утверждений в тестовой функции, и я просто ожидаю, что будет одно исключение броска? Должен ли я их разделять и помещать в независимую функцию тестирования?
Панвен Ван
Ответы:
551
<?php
require_once 'PHPUnit/Framework.php';classExceptionTestextendsPHPUnit_Framework_TestCase{publicfunction testException(){
$this->expectException(InvalidArgumentException::class);// or for PHPUnit < 5.2// $this->setExpectedException(InvalidArgumentException::class);//...and then add your test code that generates the exception
exampleMethod($anInvalidArgument);}}
Если вы используете пространства имен, вам нужно ввести полное пространство имен:$this->setExpectedException('\My\Name\Space\MyCustomException');
Alcalyn
15
Тот факт, что вы не можете назначить точную строку кода, который должен выдать, является ошибкой IMO. А неспособность проверять более одного исключения в одном тесте делает тестирование многих ожидаемых исключений действительно неуклюжим делом. Я написал реальное утверждение, чтобы попытаться решить эти проблемы.
mindplay.dk
18
К вашему сведению: по состоянию на phpunit 5.2.0setExpectedException метод устарел, заменен на метод expectException. :)
hejdav
41
То, что не упомянуто в документации или здесь, но код, который должен вызвать исключение, должен быть вызван послеexpectException() . Хотя это могло быть очевидным для некоторых, для меня это было ошибкой .
Джейсон МакКрири
7
Это не очевидно из документа, но никакой код после вашей функции, которая вызывает исключение, не будет выполнен. Поэтому, если вы хотите протестировать несколько исключений в одном тестовом примере, вы не можете.
Лоран
122
Вы также можете использовать аннотацию docblock до выхода PHPUnit 9:
@LeviMorrison - ИМХО сообщение об исключении не следует проверять, аналогично сообщениям журнала. И то, и другое считается посторонней, полезной информацией при выполнении ручной криминалистики. Ключевым моментом для проверки является тип исключения. Все, что находится за этим, слишком тесно связано с реализацией. IncorrectPasswordExceptionдолжно быть достаточно - что сообщение равно "Wrong password for bob@me.com"является вспомогательным. Добавьте к этому то, что вы хотите потратить как можно меньше времени на написание тестов, и вы начинаете понимать, насколько важными становятся простые тесты.
Дэвид Харкнесс
5
@DavidHarkness Я подумал, что кто-то поднимет это. Точно так же я бы согласился, что тестирование сообщений в целом слишком строго и жестко. Однако именно эта строгость и жесткая привязка могут (что подчеркивается целенаправленно) быть тем, что требуется в некоторых ситуациях, таких как исполнение спецификации.
Леви Моррисон
1
Я бы не смотрел в doc-блоке, чтобы понять, чего он ожидает, но я бы посмотрел на реальный тестовый код (независимо от вида теста). Это стандарт для всех других тестов; Я не вижу веских причин для того, чтобы исключения были (о боже) исключением из этого соглашения.
Kamafeather
3
Правило «не проверять сообщение» звучит правильно, если только вы не протестируете метод, который выдает один и тот же тип исключения в нескольких частях кода, с той лишь разницей, что идентификатор ошибки передается в сообщении. Ваша система может отображать сообщение для пользователя на основе сообщения об исключении (не типа исключения). В этом случае имеет значение, какое сообщение видит пользователь, следовательно, вы должны проверить сообщение об ошибке.
Код ниже будет проверять сообщение об исключении и код исключения.
Важно: он потерпит неудачу, если ожидаемое исключение не будет выдано.
try{
$test->methodWhichWillThrowException();//if this method not throw exception it must be fail too.
$this->fail("Expected exception 1162011 not thrown");}catch(MySpecificException $e){//Not catching a generic Exception or the fail function is also catched
$this->assertEquals(1162011, $e->getCode());
$this->assertEquals("Exception Message", $e->getMessage());}
$this->fail()я не думаю, что это будет использоваться таким образом, я не думаю, по крайней мере, в настоящее время (PHPUnit 3.6.11); это само по себе исключение. Используя ваш пример, если $this->fail("Expected exception not thrown")вызывается, то catchблок запускается и $e->getMessage()является «Ожидаемое исключение не брошенную» .
Кен
1
@ кен ты наверное прав. Вызов, failвероятно, принадлежит после блока catch, а не внутри try.
Фрэнк Фармер
1
Я должен понизить голос, потому что вызов failне должен быть в tryблоке. Это само по себе вызывает catchблок, выдающий ложные результаты.
Двадцать
6
Я полагаю, что причина, по которой это не работает, заключается в том, что в некоторых случаях используются все исключения catch(Exception $e). Этот метод работает очень хорошо для меня, когда я пытаюсь поймать определенные исключения:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
spyle
23
Вы можете использовать расширение assertException, чтобы утверждать более одного исключения во время одного выполнения теста.
Вставьте метод в ваш TestCase и используйте:
publicfunction testSomething(){
$test =function(){// some code that has to throw an exception};
$this->assertException( $test,'InvalidArgumentException',100,'expected message');}
Я также сделал черту для любителей хорошего кода ..
Какой PHPUnit вы используете? Я использую PHPUnit 4.7.5, и там assertExceptionне определено. Я также не могу найти его в руководстве по PHPUnit.
физическая
2
asertExceptionМетод не является частью оригинального PHPUnit. Вы должны унаследовать PHPUnit_Framework_TestCaseкласс и вручную добавить метод, связанный в посте выше . Ваши тестовые примеры будут наследовать этот унаследованный класс.
Метод PHPUnit expectExceptionочень неудобен, потому что он позволяет тестировать только одно исключение на метод тестирования.
Я сделал эту вспомогательную функцию, чтобы утверждать, что какая-то функция выдает исключение:
/**
* Asserts that the given callback throws the given exception.
*
* @param string $expectClass The name of the expected exception class
* @param callable $callback A callback which should throw the exception
*/protectedfunction assertException(string $expectClass, callable $callback){try{
$callback();}catch(\Throwable $exception){
$this->assertInstanceOf($expectClass, $exception,'An invalid exception was thrown');return;}
$this->fail('No exception was thrown');}
Добавьте его в свой тестовый класс и назовите так:
Определенно лучшее решение из всех ответов! Бросьте это в черту и упакуйте это!
Домдамброджа
11
Комплексное решение
Текущие " лучшие практики " PHPUnit для тестирования исключений кажутся .. тусклыми ( документы ).
Так как я хотел больше, чем текущая expectExceptionреализация, я использовал эту черту в своих тестовых примерах. Это всего ~ 50 строк кода .
Поддерживает несколько исключений на тест
Поддерживает утверждения, вызываемые после возникновения исключения
Надежные и понятные примеры использования
Стандартный assertсинтаксис
Поддерживает утверждения не только для сообщения, кода и класса
Поддерживает обратное утверждение, assertNotThrows
Поддерживает Throwableошибки PHP 7
Библиотека
Я опубликовал эту AssertThrowsчерту для Github и packagist, чтобы ее можно было установить с помощью composer.
Простой пример
Просто чтобы проиллюстрировать дух синтаксиса:
<?php
// Using simple callback
$this->assertThrows(MyException::class,[$obj,'doSomethingBad']);// Using anonymous function
$this->assertThrows(MyException::class,function()use($obj){
$obj->doSomethingBad();});
Довольно аккуратно?
Пример полного использования
Пожалуйста, смотрите ниже для более полного примера использования:
<?php
declare(strict_types=1);useJchook\AssertThrows\AssertThrows;usePHPUnit\Framework\TestCase;// These are just for illustrationuseMyNamespace\MyException;useMyNamespace\MyObject;finalclassMyTestextendsTestCase{useAssertThrows;// <--- adds the assertThrows methodpublicfunction testMyObject(){
$obj =newMyObject();// Test a basic exception is thrown
$this->assertThrows(MyException::class,function()use($obj){
$obj->doSomethingBad();});// Test custom aspects of a custom extension class
$this->assertThrows(MyException::class,function()use($obj){
$obj->doSomethingBad();},function($exception){
$this->assertEquals('Expected value', $exception->getCustomThing());
$this->assertEquals(123, $exception->getCode());});// Test that a specific exception is NOT thrown
$this->assertNotThrows(MyException::class,function()use($obj){
$obj->doSomethingGood();});}}?>
Немного иронично, что ваш пакет для юнит-тестирования не включает юнит-тесты в репозитории.
Домдамброджия
2
@domdambrogia благодаря @ jean-beguin теперь имеет модульные тесты.
Jchook
8
publicfunction testException(){try{
$this->methodThatThrowsException();
$this->fail("Expected Exception has not been raised.");}catch(Exception $ex){
$this->assertEquals($ex->getMessage(),"Exception message");}}
Сигнатура assertEquals()IS assertEquals(mixed $expected, mixed $actual...), реверс , как в вашем примере, поэтому он должен быть$this->assertEquals("Exception message", $ex->getMessage());
Роджер Campanera
7
Вот все утверждения об исключениях, которые вы можете сделать. Обратите внимание, что все они являются необязательными .
classExceptionTestextendsPHPUnit_Framework_TestCase{publicfunction testException(){// make your exception assertions
$this->expectException(InvalidArgumentException::class);// if you use namespaces:// $this->expectException('\Namespace\MyException');
$this->expectExceptionMessage('message');
$this->expectExceptionMessageRegExp('/essage$/');
$this->expectExceptionCode(123);// code that throws an exceptionthrownewInvalidArgumentException('message',123);}publicfunction testAnotherException(){// repeat as needed
$this->expectException(Exception::class);thrownewException('Oh no!');}}
Это неверно, потому что PHP останавливается на первом сгенерированном исключении. PHPUnit проверяет, что выброшенное исключение имеет правильный тип и говорит «тест в порядке», он даже не знает о втором исключении.
Finesse
3
/**
* @expectedException Exception
* @expectedExceptionMessage Amount has to be bigger then 0!
*/publicfunction testDepositNegative(){
$this->account->deposit(-7);}
Будьте очень осторожны "/**", обратите внимание на двойное «*». Запись только «**» (звездочка) приведет к сбою вашего кода. Также убедитесь, что вы используете последнюю версию phpUnit. В некоторых более ранних версиях phpunit @expectedException Exception не поддерживается. У меня был 4.0, и он не работал для меня, мне пришлось обновить до 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer, чтобы обновить с помощью composer.
Для PHPUnit 5.7.27 и PHP 5.6, а также для тестирования нескольких исключений в одном тесте важно было принудительно выполнить тестирование исключений. Использование только обработки исключений для утверждения экземпляра Exception пропустит тестирование ситуации, если исключение не происходит.
function yourfunction($a,$z){if($a<$z){thrownew<YOUR_EXCEPTION>;}}
вот тест
classFunctionTestextends \PHPUnit_Framework_TestCase{publicfunction testException(){
$this->setExpectedException(<YOUR_EXCEPTION>::class);
yourfunction(1,2);//add vars that cause the exception }}
PhpUnit - удивительная библиотека, но этот конкретный момент немного расстраивает. Вот почему мы можем использовать открытую библиотеку turbotesting-php, которая имеет очень удобный метод утверждения, чтобы помочь нам тестировать исключения. Это найдено здесь:
И чтобы использовать это, мы просто сделали бы следующее:
AssertUtils::throwsException(function(){// Some code that must throw an exception here},'/expected error message/');
Если код, который мы вводим внутри анонимной функции, не генерирует исключение, оно будет выброшено.
Если код, который мы печатаем внутри анонимной функции, выдает исключение, но его сообщение не соответствует ожидаемому регулярному выражению, исключение также будет выдано.
Ответы:
waitException () PHPUnit документация
Статья автора PHPUnit содержит подробное объяснение лучших практик тестирования исключений.
источник
$this->setExpectedException('\My\Name\Space\MyCustomException');
setExpectedException
метод устарел, заменен на методexpectException
. :)expectException()
. Хотя это могло быть очевидным для некоторых, для меня это было ошибкой .Вы также можете использовать аннотацию docblock до выхода PHPUnit 9:
Для PHP 5.5+ (особенно с кодом пространства имен) я сейчас предпочитаю использовать
::class
источник
IncorrectPasswordException
должно быть достаточно - что сообщение равно"Wrong password for bob@me.com"
является вспомогательным. Добавьте к этому то, что вы хотите потратить как можно меньше времени на написание тестов, и вы начинаете понимать, насколько важными становятся простые тесты.Если вы работаете на PHP 5.5+, вы можете использовать
::class
разрешение для получения имени класса с помощьюexpectException
/setExpectedException
. Это обеспечивает несколько преимуществ:string
так, это будет работать с любой версией PHPUnit.Пример:
PHP компилирует
в
без PHPUnit быть мудрее.
источник
Код ниже будет проверять сообщение об исключении и код исключения.
Важно: он потерпит неудачу, если ожидаемое исключение не будет выдано.
источник
$this->fail()
я не думаю, что это будет использоваться таким образом, я не думаю, по крайней мере, в настоящее время (PHPUnit 3.6.11); это само по себе исключение. Используя ваш пример, если$this->fail("Expected exception not thrown")
вызывается, тоcatch
блок запускается и$e->getMessage()
является «Ожидаемое исключение не брошенную» .fail
вероятно, принадлежит после блока catch, а не внутри try.fail
не должен быть вtry
блоке. Это само по себе вызываетcatch
блок, выдающий ложные результаты.catch(Exception $e)
. Этот метод работает очень хорошо для меня, когда я пытаюсь поймать определенные исключения:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
Вы можете использовать расширение assertException, чтобы утверждать более одного исключения во время одного выполнения теста.
Вставьте метод в ваш TestCase и используйте:
Я также сделал черту для любителей хорошего кода ..
источник
assertException
не определено. Я также не могу найти его в руководстве по PHPUnit.asertException
Метод не является частью оригинального PHPUnit. Вы должны унаследоватьPHPUnit_Framework_TestCase
класс и вручную добавить метод, связанный в посте выше . Ваши тестовые примеры будут наследовать этот унаследованный класс.Альтернативный способ может быть следующим:
Пожалуйста, убедитесь, что ваш тестовый класс расширяется
\PHPUnit_Framework_TestCase
.источник
Метод PHPUnit
expectException
очень неудобен, потому что он позволяет тестировать только одно исключение на метод тестирования.Я сделал эту вспомогательную функцию, чтобы утверждать, что какая-то функция выдает исключение:
Добавьте его в свой тестовый класс и назовите так:
источник
Комплексное решение
Текущие " лучшие практики " PHPUnit для тестирования исключений кажутся .. тусклыми ( документы ).
Так как я хотел больше, чем текущая
expectException
реализация, я использовал эту черту в своих тестовых примерах. Это всего ~ 50 строк кода .assert
синтаксисassertNotThrows
Throwable
ошибки PHP 7Библиотека
Я опубликовал эту
AssertThrows
черту для Github и packagist, чтобы ее можно было установить с помощью composer.Простой пример
Просто чтобы проиллюстрировать дух синтаксиса:
Довольно аккуратно?
Пример полного использования
Пожалуйста, смотрите ниже для более полного примера использования:
источник
источник
assertEquals()
ISassertEquals(mixed $expected, mixed $actual...)
, реверс , как в вашем примере, поэтому он должен быть$this->assertEquals("Exception message", $ex->getMessage());
Вот все утверждения об исключениях, которые вы можете сделать. Обратите внимание, что все они являются необязательными .
Документацию можно найти здесь .
источник
Будьте очень осторожны
"/**"
, обратите внимание на двойное «*». Запись только «**» (звездочка) приведет к сбою вашего кода. Также убедитесь, что вы используете последнюю версию phpUnit. В некоторых более ранних версиях phpunit @expectedException Exception не поддерживается. У меня был 4.0, и он не работал для меня, мне пришлось обновить до 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer, чтобы обновить с помощью composer.источник
Для PHPUnit 5.7.27 и PHP 5.6, а также для тестирования нескольких исключений в одном тесте важно было принудительно выполнить тестирование исключений. Использование только обработки исключений для утверждения экземпляра Exception пропустит тестирование ситуации, если исключение не происходит.
источник
вот тест
источник
PhpUnit - удивительная библиотека, но этот конкретный момент немного расстраивает. Вот почему мы можем использовать открытую библиотеку turbotesting-php, которая имеет очень удобный метод утверждения, чтобы помочь нам тестировать исключения. Это найдено здесь:
https://github.com/edertone/TurboTesting/blob/master/TurboTesting-Php/src/main/php/utils/AssertUtils.php
И чтобы использовать это, мы просто сделали бы следующее:
Если код, который мы вводим внутри анонимной функции, не генерирует исключение, оно будет выброшено.
Если код, который мы печатаем внутри анонимной функции, выдает исключение, но его сообщение не соответствует ожидаемому регулярному выражению, исключение также будет выдано.
источник