unitarias tutorial que pruebas ejecutar php unit-testing testing tdd

tutorial - pruebas unitarias php laravel



¿Cómo escribo pruebas unitarias en PHP? (11)

He leído en todas partes sobre lo geniales que son, pero por alguna razón no puedo entender cómo exactamente se supone que debo probar algo. ¿Podría alguien publicar un ejemplo de código y cómo lo probarían? Si no es mucho problema :)


Además de las excelentes sugerencias sobre los marcos de prueba ya dados, ¿está construyendo su aplicación con uno de los frameworks web PHP que tiene incorporadas pruebas automatizadas, como Symfony o CakePHP ? A veces, tener un lugar para simplemente dejar caer sus métodos de prueba reduce la fricción de arranque que algunas personas asocian con las pruebas automatizadas y TDD.


Demasiado para volver a publicar aquí, pero aquí hay un excelente artículo sobre el uso de phpt . Cubre una serie de aspectos en torno a phpt que a menudo se pasan por alto, por lo que podría valer la pena leer para ampliar su conocimiento de php más allá de simplemente escribir una prueba. ¡Afortunadamente el artículo también discute las pruebas de escritura!

Los principales puntos de discusión

  1. Descubra cómo los aspectos marginalmente documentados del trabajo PHP (o casi cualquier parte para el caso)
  2. Escriba pruebas de unidades simples para su propio código PHP
  3. Escribir pruebas como parte de una extensión o para transmitir un error potencial a los internos o grupos de control de calidad

Hay dos marcos que puede usar para pruebas unitarias. Simpletest y PHPUnit , que prefiero. Lea los tutoriales sobre cómo escribir y ejecutar pruebas en la página principal de PHPUnit. Es bastante fácil y bien descrito.


Hay un tercer "framework", que es mucho más fácil de aprender, incluso más fácil que Simple Test, se llama phpt.

Una guía puede encontrarse aquí: http://qa.php.net/write-test.php

Editar: acabo de ver su solicitud de código de muestra.

Supongamos que tiene la siguiente función en un archivo llamado lib.php :

<?php function foo($bar) { return $bar; } ?>

Realmente simple y directo, el parámetro que pasa, se devuelve. Entonces, veamos una prueba para esta función, llamaremos al archivo de prueba foo.phpt :

--TEST-- foo() function - A basic test to see if it works. :) --FILE-- <?php include ''lib.php''; // might need to adjust path if not in the same dir $bar = ''Hello World''; var_dump(foo($bar)); ?> --EXPECT-- string(11) "Hello World"

En pocas palabras, proporcionamos el parámetro $bar con el valor "Hello World" y var_dump() la respuesta de la llamada de función a foo() .

Para ejecutar esta prueba, use: pear run-test path/to/foo.phpt

Esto requiere una instalación funcional de PEAR en su sistema, que es bastante común en la mayoría de las circunstancias. Si necesita instalarlo, le recomiendo que instale la última versión disponible. En caso de que necesite ayuda para configurarlo, siéntase libre de preguntar (pero proporcione el sistema operativo, etc.).


Hice la mía porque no tuve tiempo para aprender otras formas de hacer las cosas, esto tomó alrededor de 20 minutos para escribir, 10 para adaptarlo para publicar aquí.

La prueba de unidad es muy útil para mí.

esto es un poco largo, pero se explica a sí mismo y hay un ejemplo en la parte inferior.

/** * Provides Assertions **/ class Assert { public static function AreEqual( $a, $b ) { if ( $a != $b ) { throw new Exception( ''Subjects are not equal.'' ); } } } /** * Provides a loggable entity with information on a test and how it executed **/ class TestResult { protected $_testableInstance = null; protected $_isSuccess = false; public function getSuccess() { return $this->_isSuccess; } protected $_output = ''''; public function getOutput() { return $_output; } public function setOutput( $value ) { $_output = $value; } protected $_test = null; public function getTest() { return $this->_test; } public function getName() { return $this->_test->getName(); } public function getComment() { return $this->ParseComment( $this->_test->getDocComment() ); } private function ParseComment( $comment ) { $lines = explode( "/n", $comment ); for( $i = 0; $i < count( $lines ); $i ++ ) { $lines[$i] = trim( $lines[ $i ] ); } return implode( "/n", $lines ); } protected $_exception = null; public function getException() { return $this->_exception; } static public function CreateFailure( Testable $object, ReflectionMethod $test, Exception $exception ) { $result = new self(); $result->_isSuccess = false; $result->testableInstance = $object; $result->_test = $test; $result->_exception = $exception; return $result; } static public function CreateSuccess( Testable $object, ReflectionMethod $test ) { $result = new self(); $result->_isSuccess = true; $result->testableInstance = $object; $result->_test = $test; return $result; } } /** * Provides a base class to derive tests from **/ abstract class Testable { protected $test_log = array(); /** * Logs the result of a test. keeps track of results for later inspection, Overridable to log elsewhere. **/ protected function Log( TestResult $result ) { $this->test_log[] = $result; printf( "Test: %s was a %s %s/n" ,$result->getName() ,$result->getSuccess() ? ''success'' : ''failure'' ,$result->getSuccess() ? '''' : sprintf( "/n%s (lines:%d-%d; file:%s)" ,$result->getComment() ,$result->getTest()->getStartLine() ,$result->getTest()->getEndLine() ,$result->getTest()->getFileName() ) ); } final public function RunTests() { $class = new ReflectionClass( $this ); foreach( $class->GetMethods() as $method ) { $methodname = $method->getName(); if ( strlen( $methodname ) > 4 && substr( $methodname, 0, 4 ) == ''Test'' ) { ob_start(); try { $this->$methodname(); $result = TestResult::CreateSuccess( $this, $method ); } catch( Exception $ex ) { $result = TestResult::CreateFailure( $this, $method, $ex ); } $output = ob_get_clean(); $result->setOutput( $output ); $this->Log( $result ); } } } } /** * a simple Test suite with two tests **/ class MyTest extends Testable { /** * This test is designed to fail **/ public function TestOne() { Assert::AreEqual( 1, 2 ); } /** * This test is designed to succeed **/ public function TestTwo() { Assert::AreEqual( 1, 1 ); } } // this is how to use it. $test = new MyTest(); $test->RunTests();

Esto produce:

Test: TestOne was a failure /** * This test is designed to fail **/ (lines:149-152; file:/Users/kris/Desktop/Testable.php) Test: TestTwo was a success


Las pruebas de codecepción son muy parecidas a las pruebas unitarias comunes, pero son mucho más potentes en los casos en los que se requieren burlas y trozos.

Aquí está la prueba del controlador de muestra. Observe cómo fácilmente se crean los talones. Qué tan fácil es verificar el método invocado.

<?php use Codeception/Util/Stub as Stub; const VALID_USER_ID = 1; const INVALID_USER_ID = 0; class UserControllerCest { public $class = ''UserController''; public function show(CodeGuy $I) { // prepare environment $I->haveFakeClass($controller = Stub::makeEmptyExcept($this->class, ''show'')); $I->haveFakeClass($db = Stub::make(''DbConnector'', array(''find'' => function($id) { return $id == VALID_USER_ID ? new User() : null ))); }; $I->setProperty($controller, ''db'', $db); $I->executeTestedMethodOn($controller, VALID_USER_ID) ->seeResultEquals(true) ->seeMethodInvoked($controller, ''render''); $I->expect(''it will render 404 page for non existent user'') ->executeTestedMethodOn($controller, INVALID_USER_ID) ->seeResultNotEquals(true) ->seeMethodInvoked($controller, ''render404'',''User not found'') ->seeMethodNotInvoked($controller, ''render''); } }

También hay otras cosas interesantes. Puede probar el estado de la base de datos, el sistema de archivos, etc.


Obtener PHPUnit. Es muy fácil de usar.

Luego comience con afirmaciones muy simples. Puedes hacer mucho con AssertEquals antes de entrar en cualquier otra cosa. Esa es una buena manera de mojarse los pies.

También puede intentar escribir su prueba primero (ya que le dio a su pregunta la etiqueta TDD) y luego escribir su código. Si no has hecho esto antes, es una revelación.

require_once ''ClassYouWantToTest''; require_once ''PHPUnit...blah,blah,whatever''; class ClassYouWantToTest extends PHPUnit...blah,blah,whatever { private $ClassYouWantToTest; protected function setUp () { parent::setUp(); $this->ClassYouWantToTest = new ClassYouWantToTest(/* parameters */); } protected function tearDown () { $this->ClassYouWantToTest = null; parent::tearDown(); } public function __construct () { // not really needed } /** * Tests ClassYouWantToTest->methodFoo() */ public function testMethodFoo () { $this->assertEquals( $this->ClassYouWantToTest->methodFoo(''putValueOfParamHere), ''expectedOutputHere); /** * Tests ClassYouWantToTest->methodBar() */ public function testMethodFoo () { $this->assertEquals( $this->ClassYouWantToTest->methodBar(''putValueOfParamHere), ''expectedOutputHere); }


Para pruebas simples y documentación, php-doctest es bastante agradable y es una forma muy fácil de comenzar, ya que no tiene que abrir un archivo por separado. Imagina la función a continuación:

/** * Sums 2 numbers * <code> * //doctest: add * echo add(5,2); * //expects: * 7 * </code> */ function add($a,$b){ return $a + $b; }

Si ahora ejecuta este archivo a través de phpdt (línea de comando runner de php-doctest) se ejecutará 1 prueba. El doctest está contenido dentro del bloque <code>. Doctest se originó en python y está bien para dar ejemplos útiles y ejecutables sobre cómo se supone que el código funciona. No se puede utilizar exclusivamente porque el código en sí mismo se acumularía con casos de prueba, pero he descubierto que es útil junto con una biblioteca tdd más formal: yo uso phpunit.

Esta primera respuesta here resume muy bien (no es unidad versus doctest).



Sé que ya hay mucha información aquí, pero como esto todavía aparece en las búsquedas de Google, también podría agregar Chinook Test Suite a la lista. Es un marco de prueba simple y pequeño.

Puede probar fácilmente sus clases con él y también crear objetos simulados. Ejecuta las pruebas a través de un navegador web y (todavía no) a través de una consola. En el navegador puede especificar qué clase de prueba o incluso qué método de prueba ejecutar. O simplemente puede ejecutar todas las pruebas.

Una captura de pantalla de la página de github:

Lo que me gusta de esto es la forma en que afirmas las pruebas. Esto se hace con las llamadas "afirmaciones fluidas". Ejemplo:

$this->Assert($datetime)->Should()->BeAfter($someDatetime);

Y crear objetos falsos también es pan comido (con una sintaxis similar a la fluida):

$mock = new CFMock::Create(new DummyClass()); $mock->ACallTo(''SomeMethod'')->Returns(''some value'');

De todos modos, se puede encontrar más información en la página de github con un ejemplo de código también:

https://github.com/w00/Chinook-TestSuite


phpunit es prácticamente el marco de pruebas de unidades de facto para php. también está php-doctest (disponible como paquete PEAR) y algunos otros. php en sí mismo se prueba para regresiones y similares a través de http://qa.php.net/write-test.php que también se pueden ejecutar a través de pera.