Tú lo sabes; Lo sé. Deberíamos probar nuestro código más que nosotros. Parte de la razón por la que no lo hacemos, creo, es que no sabemos exactamente cómo. Bueno, hoy me estoy deshaciendo de esa excusa: te estoy enseñando a probar tu PHP con el marco EnhancePHP.
No intentaré convencerte de que pruebes tu código; y tampoco vamos a discutir el desarrollo dirigido por pruebas. Eso se ha hecho antes en Nettuts +. En ese artículo, Nikko Bautista explica exactamente por qué las pruebas son una buena cosa y describe un flujo de trabajo TDD. Lee eso alguna vez, si no estás familiarizado con TDD. También usa la biblioteca SimpleTest para sus ejemplos, así que si no te gusta el aspecto de EnhancePHP, puedes probar SimpleTest como alternativa.
Como dije, usaremos el EnhancePHP. Es una gran pequeña biblioteca de PHP, un solo archivo, que ofrece muchas funciones de prueba..
Comience dirigiéndose a su página de descarga y agarrando la última versión del marco.
Vamos a construir una clase de validación realmente simple para probar. No va a hacer mucho: solo vuelve cierto
si el artículo pasa la validación, o falso
si no lo hace Entonces, configura un pequeño proyecto realmente simple:
Haremos esto es una moda semi-TDD, así que comencemos escribiendo algunas pruebas.
Nuestra pequeña clase va a validar tres cosas: direcciones de correo electrónico, nombres de usuario y números de teléfono.
Pero antes de comenzar a escribir las pruebas reales, tendremos que configurar nuestra clase:
val = nueva Validación ();
Este es nuestro comienzo; Note que estamos extendiendo la clase. \ Enhance \ TestFixture
. Al hacerlo, le informamos a EnhancePHP que todos los métodos públicos de esta clase son pruebas, con la excepción de los métodos preparar
y demoler
. Como puede imaginar, estos métodos se ejecutan antes y después de todas las pruebas (no antes y después de cada una). En este caso, nuestra preparar
método creará una nueva Validación
instancia y asignarlo a una propiedad en nuestra instancia.
Por cierto, si eres relativamente nuevo en PHP, es posible que no estés familiarizado con eso. \ Enhance \ TestFixture
sintaxis: ¿qué pasa con las barras? Eso es el espacio de nombres PHP para ti; Echa un vistazo a los documentos si no está familiarizado con él.
Entonces, las pruebas!
Vamos a empezar por validar las direcciones de correo electrónico. Como verás, solo hacer una prueba básica es bastante simple:
función pública validates_a_good_email_address () $ result = $ this-> val-> validate_email ("[email protected]"); \ Enhance \ Assert :: isTrue ($ result);
Simplemente llamamos al método que queremos probar, le pasamos una dirección de correo electrónico válida y almacenamos $ resultado
. Entonces, entregamos $ resultado
al es verdad
método. Ese método pertenece a la \ Enhance \ Assert
clase.
Queremos asegurarnos de que nuestra clase rechace direcciones que no sean de correo electrónico. Entonces, vamos a probar para eso:
función pública reject_bad_email_addresses () $ val_wrapper = \ Enhance \ Core :: getCodeCoverageWrapper ('Validation'); $ val_email = $ this-> get_scenario ('validate_email'); $ address = array ("john", "[email protected]", "john @ doe.", "jo*[email protected]"); foreach ($ address as $ addr) $ val_email-> with ($ addr) -> expect (false); $ val_email-> verifyExpectations ();
Esto introduce una característica bastante buena de EnhancePHP: escenarios. Queremos probar un montón de direcciones que no sean de correo electrónico para asegurarnos de que nuestro método retornará falso
. Al crear un escenario, esencialmente envolvemos una instancia de nuestra clase en algo de bondad de EnhancePHP, escribimos mucho menos código para probar todas nuestras no direcciones. Eso es lo que $ val_wrapper
es: una instancia modificada de nuestro Validación
clase. Entonces, $ val_email
es el objeto de escenario, algo así como un atajo a la validar correo electrónico
método.
Luego, tenemos una serie de cadenas que no deben validarse como direcciones de correo electrónico. Iremos sobre esa matriz con una para cada
lazo. Observe cómo ejecutamos la prueba: llamamos al con
Método en nuestro objeto de escenario, pasándole los parámetros para el método que estamos probando. Entonces, llamamos al esperar
Método en eso, y pasarlo todo lo que esperamos volver.
Finalmente, llamamos al escenario verifique las expectativas
método.
Así, las primeras pruebas están escritas; como los manejamos?
Antes de ejecutar las pruebas, tendremos que crear nuestro Validación
clase. Dentro lib.validation.php
, empieza con esto:
Ahora en
prueba.php
, lo haremos todo juntoPrimero, necesitaremos todos los archivos necesarios. Entonces, llamamos al
pruebas de ejecución
Método, que encuentra nuestras pruebas..Luego viene la parte limpia. Enciende un servidor y obtendrás una buena salida HTML:
Muy bonito, ¿verdad? Ahora, si tienes PHP en tu terminal, ejecuta esto en la terminal:
EnhancePHP advierte que estás en un entorno diferente y ajusta su salida de manera apropiada. Un beneficio adicional de esto es que si está utilizando un IDE, como PhpStorm, que puede ejecutar pruebas unitarias, puede ver esta salida de terminal dentro del IDE..
También puede obtener salida XML y TAP, si eso es lo que prefiere, simplemente pase
\ Enhance \ TemplateType :: Xml
o\ Enhance \ TemplateType :: Tap
alpruebas de ejecución
Método para obtener la salida adecuada. Tenga en cuenta que ejecutarlo en el terminal también producirá resultados de línea de comandos, sin importar a qué pase.pruebas de ejecución
.Haciendo pasar las pruebas
Vamos a escribir el método que hace que nuestras pruebas pasen. Como ustedes saben, esa es la
validar correo electrónico
. En la parte superior de laValidación
clase, vamos a definir una propiedad pública:public $ email_regex = '/^[\w+-_\.◆++ |\\\\\\\\\\\\\\++';Estoy poniendo esto en una propiedad pública para que si el usuario quiere reemplazarlo con su propia expresión regular, podría hacerlo. Estoy usando esta versión simple de una expresión regular de correo electrónico, pero puede reemplazarla con su expresión regular favorita si lo desea.
Luego, está el método:
función pública validate_email ($ dirección) return preg_match ($ this-> email_regex, $ dirección) == 1Ahora, volvemos a ejecutar las pruebas, y:
Escribiendo más pruebas
Tiempo para más pruebas:
Nombres de usuario
Vamos a crear algunas pruebas para nombres de usuario ahora. Nuestros requisitos son simplemente que debe ser una cadena de 4 a 20 caracteres que consiste solo en caracteres de palabra o puntos. Asi que:
función pública validates_a_good_username () $ result = $ this-> val-> validate_username ("some_user_name.12"); \ Enhance \ Assert :: isTrue ($ result);Ahora, ¿qué tal unos pocos nombres de usuario que no deberían validar?
función pública rejects_bad_usernames () $ val_username = $ this-> get_scenario ('validate_username'); $ usernames = array ("name with space", "no! exclaimation! mark", "ts", "thisUsernameIsTooLongItShouldBeBetweenFourAndTwentyCharacters"); foreach ($ usernames as $ name) $ val_username-> with ($ name) -> expect (false); $ val_username-> verifyExpectations ();Esto es muy similar a nuestro
reject_bad_email_addresses
función. Tenga en cuenta, sin embargo, que estamos llamando a estoget_scenario
Método: ¿De dónde viene eso? Estoy abstrayendo la funcionalidad de creación de escenarios en un método privado, al final de nuestra clase:función privada get_scenario ($ method) $ val_wrapper = \ Enhance \ Core :: getCodeCoverageWrapper ('Validation'); return \ Enhance \ Core :: getScenario ($ val_wrapper, $ method);Podemos usar esto en nuestro
reject_bad_usernames
y reemplazar la creación de escenarios enreject_bad_email_addresses
también. Debido a que este es un método privado, EnhancePHP no intentará ejecutarlo como una prueba normal, como lo hará con métodos públicos.Haremos que estas pruebas se aprueben de manera similar a como hicimos la primera serie de pases:
# En la parte superior ... public $ username_regex = '/^[\w\.◆4,20$/'; # y el método ... función pública validate_username ($ username) return preg_match ($ this-> username_regex, $ username) == 1;Esto es bastante básico, por supuesto, pero eso es todo lo que se necesita para cumplir nuestro objetivo. Si quisiéramos devolver una explicación en caso de falla, puede hacer algo como esto:
función pública validate_username ($ username) $ len = strlen ($ username); si ($ len < 4 || $len > 20) return "El nombre de usuario debe tener entre 4 y 20 caracteres"; elseif (preg_match ($ this-> username_regex, $ username) == 1) return true; else return "El nombre de usuario solo debe incluir letras, números, guiones bajos o puntos.";Por supuesto, también es posible que desee comprobar si el nombre de usuario ya existe.
Ahora, ejecuta las pruebas y deberías verlas pasar todas.
Números de teléfono
Creo que ya te has acostumbrado a esto, así que terminemos nuestro ejemplo de validación revisando los números de teléfono:
función pública validates_good_phonenumbers () $ val_phonenumber = $ this-> get_scenario ("validate_phonenumber"); $ numbers = array ("1234567890", "(890) 123-4567", "123-456-7890", "123 456 7890", "(123) 456 7890"); foreach ($ numbers as $ num) $ val_phonenumber-> with ($ num) -> expect (true); $ val_phonenumber-> verifyExpectations (); función pública rejects_bad_phonenumnbers () $ result = $ this-> val-> validate_phonenumber ("123456789012"); \ Enhance \ Assert :: isFalse ($ result);Probablemente puedas averiguar la
Validación
método:public $ phonenumber_regex = '/ ^ \ d 10 $ | ^ (\ (? \ d 3 \)? [| -] \ d 3 [| -] \ d 4) $ /'; función pública validate_phonenumber ($ number) return preg_match ($ this-> phonenumber_regex, $ number) == 1;Ahora, podemos ejecutar todas las pruebas juntos. Esto es lo que se ve desde la línea de comandos (mi entorno de prueba preferido):
Otra funcionalidad de prueba
Por supuesto, EnhancePHP puede hacer mucho más de lo que hemos visto en este pequeño ejemplo. Veamos algo de eso ahora..
Nos reunimos brevemente el
\ Enhance \ Assert
Clase en nuestra primera prueba. Realmente no lo usamos de otra manera, porque no es útil cuando se usan escenarios. Sin embargo, es donde están todos los métodos de afirmación. La belleza de ellos es que sus nombres hacen que su funcionalidad sea increíblemente obvia. Los siguientes ejemplos de prueba pasarían:
\ Enhance \ Assert :: areIdentical ("Nettuts +", "Nettuts +")
\ Enhance \ Assert :: areNotIdentical ("Nettuts +", "Psdtuts +")
\ Enhance \ Assert :: isTrue (true)
\ Enhance \ Assert :: isFalse (false)
\ Enhance \ Assert :: contiene ("Net", "Nettuts +")
\ Enhance \ Assert :: isNull (null)
\ Enhance \ Assert :: isNotNull ('Nettust +')
\ Enhance \ Assert :: isInstanceOfType ('Exception', new Exception (""))
\ Enhance \ Assert :: isNotInstanceOfType ('String', nueva excepción (""))
También hay algunos otros métodos de afirmación; Puede consultar los documentos para obtener una lista completa y ejemplos.
EnhancePHP también puede hacer mocks y stubs. ¿No has oído hablar de burlas y talones? Bueno, no son demasiado complicados. Un simulacro es un envoltorio para objeto, que puede realizar un seguimiento de los métodos que se llaman, con las propiedades que se llaman y los valores devueltos. Un simulacro tendrá alguna prueba para verificar, como veremos..
Aquí hay un pequeño ejemplo de una burla. Empecemos con una clase muy simple que cuenta:
num = $ this-> num + $ num; devuelve $ this-> num;
Tenemos una función: incremento
, que acepta un parámetro (pero por defecto es 1), e incrementa el $ num
propiedad por ese número.
Podríamos usar esta clase si estuviéramos construyendo un marcador:
Cuadro de indicadores de clase public $ home = 0; public $ away = 0; función pública __construct ($ home, $ away) $ this-> home_counter = $ home; $ this-> away_counter = $ away; función pública score_home () $ this-> home = $ this-> home_counter-> increment (); devuelve $ this-> home; función pública score_away () $ this-> away = $ this-> away_counter-> increment (); devuelve $ this-> home;
Ahora, queremos probar para asegurarnos de que el Mostrador
método de instancia incremento
está funcionando correctamente cuando el Marcador
Los métodos de instancia lo llaman. Así que creamos esta prueba:
la clase ScoreboardTest extiende \ Enhance \ TestFixture función pública score_home_calls_increment () $ home_counter_mock = \ Enhance \ MockFactory :: createMock ("Counter"); $ away_counter = new Counter (); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment')); $ scoreboard = new Scoreboard ($ home_counter_mock, $ away_counter); $ scoreboard-> score_home (); $ home_counter_mock-> verifyExpectations (); \ Enhance \ Core :: runTests ();
Nótese que comenzamos creando $ home_counter_mock
: usamos la fábrica de simulacros de EnhancePHP, pasándole el nombre de la clase de la que nos estamos burlando. Esto devuelve una instancia "envuelta" de Mostrador
. Luego, sumamos una expectativa, con esta línea.
$ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment'));
Nuestra expectativa solo dice que esperamos la incremento
método para ser llamado.
Después de eso, vamos a crear el Marcador
instancia y llamada score_home
. Entonces nosotros verifique las expectativas
. Si ejecutas esto, verás que nuestra prueba pasa..
También podríamos indicar con qué parámetros queremos que se llame a un método en el objeto simulado, qué valor se devuelve o cuántas veces se debe llamar al método, con algo como esto:
$ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> with (10)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> times (2)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> devuelve (1)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('increment') -> with (3) -> times (1)); $ home_counter_mock-> addExpectation (\ Enhance \ Expect :: method ('incremento') -> con (2) -> devuelve (2));
Debo mencionar que, mientras con
y veces
mostrará las pruebas fallidas si las expectativas no se significan, devoluciones
no lo hace Tendrá que almacenar el valor de retorno y usar una aserción para eso. No estoy seguro de por qué ese es el caso, pero cada biblioteca tiene sus peculiaridades :). (Puedes ver un ejemplo de esto en los ejemplos de biblioteca en Github).
Luego, hay talones. Un código auxiliar se llena para un objeto y método real, devolviendo exactamente lo que le dices. Entonces, digamos que queremos asegurarnos de que nuestros Marcador
la instancia está utilizando correctamente el valor que recibe de incremento
, podemos tachar un Mostrador
instancia para que podamos controlar lo incremento
volverá:
la clase ScoreboardTest extiende \ Enhance \ TestFixture public function score_home_calls_increment () $ home_counter_stub = \ Enhance \ StubFactory :: createStub ("Counter"); $ away_counter = new Counter (); $ home_counter_stub-> addExpectation (\ Enhance \ Expect :: method ('increment') -> devuelve (10)); $ scoreboard = new Scoreboard ($ home_counter_stub, $ away_counter); $ result = $ scoreboard-> score_home (); \ Enhance \ Assert :: areIdentical ($ result, 10); \ Enhance \ Core :: runTests ();
Aquí estamos usando \ Enhance \ StubFactory :: createStub
para crear nuestro contador de stub. Luego, agregamos la expectativa de que el método. incremento
devolverá 10. Podemos ver que el resultado es lo que esperaríamos, dado nuestro código.
Para ver más ejemplos de simulacros y apéndices con la biblioteca EnhancePHP, echa un vistazo a Github Repo.
Bueno, eso es un vistazo a las pruebas en PHP, utilizando el marco EnhancePHP. Es un marco increíblemente simple, pero proporciona todo lo que necesita para hacer algunas pruebas unitarias simples en su código PHP. Incluso si elige un método / marco de trabajo diferente para probar su PHP (¡o quizás haga su propio rollo!), Espero que este tutorial haya despertado el interés en probar su código, y lo sencillo que puede ser..
Pero tal vez usted ya prueba su PHP. Háganos saber lo que utiliza en los comentarios; ¡Después de todo, todos estamos aquí para aprender unos de otros! Muchas gracias por pasar por aquí!