2011-04-16 31 views
196

¿Alguien sabe si hay un assert o algo así que puede probar si se lanzó una excepción en el código que se está probando?PHPUnit afirman que se lanzó una excepción?

+1

Para esas respuestas: ¿qué pasa multi-aseveraciones en una función de prueba, y solo espero tener una excepción de tiro? ¿TENGO que separarlos y poner el uno en una función de prueba independiente? –

Respuesta

311
<?php 
require_once 'PHPUnit/Framework.php'; 

class ExceptionTest extends PHPUnit_Framework_TestCase 
{ 
    public function 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); 
    } 
} 

expectException() PHPUnit documentation

PHPUnit author article proporciona explicaciones detalladas de probar las excepciones mejores prácticas.

+58

+1 por no confiar en el doc-block mágico – SuperFamousGuy

+6

Si usa espacios de nombres, debe ingresar el espacio de nombre completo: '$ this-> setExpectedException ('\ My \ Name \ Space \ MyExceptionException');' – Alcalyn

+2

Tenga en cuenta que no parece haber una manera de esperar explícitamente ninguna excepción. Solo tiene que llamar a su método y, si se lanza una excepción, la prueba fallará automáticamente. –

91

También se puede utilizar un docblock annotation:

class ExceptionTest extends PHPUnit_Framework_TestCase 
{ 
    /** 
    * @expectedException InvalidArgumentException 
    */ 
    public function testException() 
    { 
     ... 
    } 
} 

Para PHP 5.5 o superior (en especial con código de espacio de nombres), ahora prefieren usar ::class Código

+2

IMO, este es el método preferido. –

+3

@MikePurcell, ¿por qué? –

+0

@ Prof.Falken: preferencia personal. La anotación de Docblock mantiene el método de prueba limpio, y varios frameworks están haciendo uso de la misma práctica; symfony 2, zf2. –

23

continuación mensaje de excepción y el código de excepción pondrá a prueba.

Importante: Fallará si no se lanza una excepción esperada.

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()); 
} 
+5

'$ this-> fail()' no está destinado a ser utilizado de esta manera, no creo, al menos no actualmente (PHPUnit 3.6.11); actúa como una excepción en sí misma. Usando su ejemplo, si '$ this-> fail (se llama" excepción esperada no lanzada ")', se activa el bloque 'catch' y' $ e-> getMessage() 'es _" excepción esperada no lanzada "_ . – ken

+1

@ken probablemente tengas razón. La llamada a 'fail' probablemente pertenece * después de * el bloque catch, no dentro del try. –

+1

Tengo que rechazarlo porque la llamada a 'fail' no debería estar en el bloque' try'. En sí mismo desencadena el bloqueo 'catch' produciendo resultados falsos. – Twifty

21

Puede utilizar assertException extension hacer valer más de una excepción durante una ejecución de prueba.

método Insert en su TestCase y uso:

public function testSomething() 
{ 
    $test = function() { 
     // some code that has to throw an exception 
    }; 
    $this->assertException($test, 'InvalidArgumentException', 100, 'expected message'); 
} 

También hizo una trait para los amantes del código de buen ..

+0

¿Qué PHPUnit estás usando? Estoy usando PHPUnit 4.7.5, y allí 'assertException' no está definido. Tampoco puedo encontrarlo en el manual de PHPUnit. – physicalattraction

+1

El método 'asertException' no es parte de PHPUnit original. Debe heredar la clase 'PHPUnit_Framework_TestCase' y agregar [método vinculado en la publicación anterior] (https://gist.github.com/VladaHejda/8826707) manualmente. Sus casos de prueba heredarán esta clase heredada. – hejdav

7
public function testException() { 
    try { 
     $this->methodThatThrowsException(); 
     $this->fail("Expected Exception has not been raised."); 
    } catch (Exception $ex) { 
     $this->assertEquals($ex->getMessage(), "Exception message"); 
    } 

} 
26

Si se está ejecutando en PHP 5.5 o superior, puede usar ::class resolution para obtener el nombre de la clase con expectException/setExpectedException. Esto proporciona varios beneficios:

  • El nombre será totalmente calificado con su espacio de nombres (si corresponde).
  • Se resuelve en string por lo que funcionará con cualquier versión de PHPUnit.
  • Obtiene la finalización del código en su IDE.
  • El compilador de PHP emitirá un error si escribe mal el nombre de la clase.

Ejemplo:

namespace \My\Cool\Package; 

class AuthTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testLoginFailsForWrongPassword() 
    { 
     $this->expectException(WrongPasswordException::class); 
     Auth::login('Bob', 'wrong'); 
    } 
} 

PHP compila

WrongPasswordException::class 

en

"\My\Cool\Package\WrongPasswordException" 

sin PHPUnit siendo el más prudente.

Nota: PHPUnit 5.2 introducedexpectException como un reemplazo para setExpectedException.

1
/** 
* @expectedException Exception 
* @expectedExceptionMessage Amount has to be bigger then 0! 
*/ 
public function testDepositNegative() 
{ 
    $this->account->deposit(-7); 
} 

Sé muy cuidadoso acerca "/**", observe el doble "*". Escribir solo "* *" (asterix) fallará su código. También asegúrese de usar la última versión de phpUnit. En algunas versiones anteriores de phpunit @expectedException, la excepción no es compatible. Tenía 4.0 y no funcionó, tuve que actualizar a 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer para actualizar con el compositor.

6

Una forma alternativa puede ser la siguientes aparatos:

$this->expectException(\Exception::class); 
$this->expectExceptionMessage('Expected Exception Message'); 

Por favor asegúrese de que sus extensiones de clase Test \ PHPUnit_Framework_TestCase

4

He aquí todas las afirmaciones de excepción que puede hacer. Tenga en cuenta que todos ellos son opcionales.

class ExceptionTest extends PHPUnit_Framework_TestCase 
{ 
    public function testException() 
    { 
     // make your exception assertions 
     $this->expectException(InvalidArgumentException::class); 
     // if you use namespaces: 
     // $this->expectException('\Namespace\MyExceptio‌​n'); 
     $this->expectExceptionMessage('message'); 
     $this->expectExceptionMessageRegExp('/essage$/'); 
     $this->expectExceptionCode(123); 
     // code that throws an exception 
     throw new InvalidArgumentException('message', 123); 
    } 

    public function testAnotherException() 
    { 
     // repeat as needed 
     $this->expectException(Exception::class); 
     throw new Exception('Oh no!'); 
    } 
} 

documentación se puede encontrar here.

+0

Es incorrecto porque PHP se detiene en la primera excepción lanzada. PHPUnit comprueba que la excepción arrojada tiene el tipo correcto y dice «la prueba está bien», ni siquiera conoce la segunda excepción. – Finesse

+0

@Finesse FTFY ... – Potherca

1

El método PHPUnit expectException es muy inconveniente porque permite probar solo una excepción por método de prueba.

He hecho esta función auxiliar para afirmar que alguna función lanza una excepción:

/** 
* 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 
*/ 
protected function assertException(string $expectClass, callable $callback) 
{ 
    try { 
     $callback(); 
    } catch (\Throwable $exception) { 
     $this->assertInstanceOf($expectClass, $exception); 
     return; 
    } 

    $this->fail('No exception was thrown'); 
} 

añadirlo a su clase de prueba y la llamada de esta forma:

public function testSomething() { 
    $this->assertException(\PDOException::class, function() { 
     new \PDO('bad:param'); 
    }); 
    $this->assertException(\PDOException::class, function() { 
     new \PDO('foo:bar'); 
    }); 
} 
Cuestiones relacionadas