2010-11-17 11 views
12

Esto siempre me ha molestado. ¿Por qué la gente dice que la prueba unitaria en rspec pero la prueba de integración en pepino? No estoy preguntando por qué estas pruebas son necesarias. Sé cuál es la diferencia entre la integración y la prueba unitaria. Simplemente no veo por qué, dada la sintaxis completamente personalizable de pepino, no se usa para pruebas unitarias.¿Por qué el pepino se considera una herramienta de prueba de integración en lugar de una herramienta de prueba de la unidad?

Me parece que se escribe la misma cantidad de código para pepino y rspec, la única diferencia es que para el pepino se separa la lógica de prueba de la escritura de prueba.

+2

JBehave 1.0 fue primero - originalmente con mecanismos separados para ejemplos de clase/pruebas y escenarios. Este fue el momento de JUnit 3.8 - JUnit 4.4 hizo innecesario el ejemplo de clase. Dan North (fundador de BDD y JBehave) desarrolló RBehave, luego el equipo de RSpec lo integró, luego David Chelimsky lo hizo usar texto plano y lo dividieron en una biblioteca separada. Creo que Aslak Hellesoy dirigió esto. Luego reescribimos JBehave 2.0 basado en Cucumber. Para interés histórico: http://blog.davidchelimsky.net/2007/10/25/plain-text-stories-part-iii/ – Lunivore

+0

Ah, y Cucumber es un poco más lento para escribir. Vea mi respuesta por la razón y los problemas que resuelven los marcos. – Lunivore

Respuesta

7

Hay un montón de sobrecarga en el uso de pepino para las pruebas unitarias. No solo tiene que escribir las características, sino luego asignarlas a la implementación usando un bit de código separado.

Las pruebas unitarias deben ser muy rápidas de escribir y muy rápidas de ejecutar. Naturalmente, pepino se centra en la experiencia del usuario final, principalmente debido al lenguaje utilizado para escribir una característica.

Sólo para refrescar, una característica podría contener lo siguiente:

Como algunos de los interesados ​​de un sistema
me gustaría realizar una actividad
Para que pueda obtener algún beneficio de ella

Given a precondition 
When I perform an action 
Then something should happen 

El párrafo inicial, que a menudo se ignora, es muy importante, ya que establece un cont ext para la operación y explica por qué sucede algo. Debido al uso del lenguaje natural, estas cosas son fáciles de mostrar a los no programadores a fin de obtener algunos comentarios.

Ahora, usar estos para pruebas unitarias parecería incómodo en el mejor de los casos. En primer lugar, el enfoque del usuario final sugiere un enfoque de integración más, ya que la característica no dice nada acerca de los simuladores y la separación UI/lógica. Es decir. una función como la siguiente sólo parece raro:

Given a that a database mock is configured with the following data 
| ID | Username | 
| 0 | igor  | 
When call FindAll on User Repository 
Then I get the following user back 
| ID | Username | 
| 0 | igor  | 

Además, como el SUT se hace más pequeño (es decir, una clase), el contexto de la operación no es tan importante. Un repositorio de usuario no se preocupa por el contexto, p. no importa si el consumidor es un usuario normal o un usuario VIP. Un componente simple (que debería ser, después de SRP), es completamente determinista en función de sus entradas.

Por lo tanto, la prueba unitaria está ahí para validar que lo que escribió es correcto y la prueba de cucmber está ahí para validar que lo que escribió satisface un propósito más elevado al poner el comportamiento del sistema en un contexto.

+0

¿Qué hay de reutilizar el código de prueba escribiendo las definiciones de paso? ¿Eso no importa? – inf3rno

+0

que podía imaginar algo como esto: 'característica los usuarios se conservan por el depósito de usuarios \t usuarios Escenario encontrar con el repositorio \t \t Teniendo en cuenta que el almacenamiento contiene Igor único usuario \t \t Cuando pregunto el repositorio para encontrar todos los usuarios \t \t Luego solo obtengo el usuario igor back' - esto es más abstracto, pero es difícil mapear estos términos en UserRepository.FindAll y en MockDatabase – inf3rno

1

La idea general es que las pruebas de Cucumber están escritas en un nivel más alto que las pruebas de unidades tradicionales. Por ejemplo, cuando prueba un módulo en particular, se concentra en probar solo la funcionalidad de los módulos, aisladamente del resto del sistema. La interfaz con otras partes del sistema generalmente debería representarse con objetos simulados.

Pepino por otro lado se centra en las pruebas del sistema desde la interfaz de usuario a través de la capa de persistencia de datos.

Pruebas unitarias = Ingeniero mecánico probando su nuevo motor en un entorno de laboratorio montado en un arnés.

Prueba de pepino = Controlador de prueba poniéndolo en una pista para dar un giro.

+0

Pero ese es el problema. Nada de lo que dijiste es específico de rspec, y no hay nada que el pepino no pueda hacer. Debajo de los escenarios, el pepino es solo un código de rubí regular, que puede incluir burlas y pruebas a nivel de clase. Entonces, ¿por qué no? – ryeguy

+0

Claro, tienes razón, es solo código debajo de todo. Donde hay código existe la posibilidad de hacer lo que se desee con la suficiente persistencia. Sin embargo, ese modelo de prueba no es la intención de Pepino y sería un fracaso para el propósito de la prueba completa del sistema de pila si comenzaras a burlarte de los objetos. Parece que quieres usar un destornillador para conducir las uñas. – danielz

+1

Aún no está siendo lo suficientemente específico. ¿Por qué ** exactamente ** es rspec más adecuado para esto? El hecho de que estoy haciendo 2 tipos diferentes de pruebas no significa que deba usar 2 marcos diferentes. Hay muchos marcos de burla desacoplados que se pueden usar fácilmente desde dentro del pepino. Con rspec y pepino escribes nombres de prueba descriptivos, entonces, ¿cómo es diferente? Cuando se trata de eso, la diferencia es que los escenarios del pepino están en un archivo separado. No solo diga "bueno, nada lo detiene". Yo sé eso. Solo quiero saber por qué todos piensan que está mal. – ryeguy

4

Cucumber resuelve un conjunto particular de problemas: involucrar a las partes interesadas del negocio que no pueden leer fácilmente el código y ciertamente no pueden escribirlo, y proporcionar reutilización entre los pasos en escenarios automatizados. Los escenarios también suelen abarcar más de un aspecto del comportamiento, documentan la funcionalidad de todo el sistema y, a menudo, abarcan recorridos completos de usuarios a través de múltiples componentes. La arquitectura basada en pasos que fomenta Cucumber es ideal para manejar estos escenarios.

También presenta una serie de otros problemas. En primer lugar, debe vincular los escenarios de Pepino a un conjunto de accesorios, por lo que hay otra capa de abstracción que los hace más lentos para escribir. En segundo lugar, el inglés es más difícil de refactorizar que el código, incluso con lenguajes dinámicos como Ruby (la diferencia es aún más pronunciada en C# y las variantes de Java como JBehave, SpecFlow, Cuke4Nuke y Cuke4Duke). Es más difícil saber si aún se están utilizando los pasos, y más difícil mantener los escenarios. También es más difícil administrar el estado entre los diversos pasos.

Con pruebas unitarias, el público es técnico. Las clases idealmente tienen responsabilidades únicas con poca o ninguna duplicación, por lo que la reutilización de los pasos no es importante. Cuando queremos cambiar un elemento de código, tendemos a buscar pruebas cuyas convenciones de nombres coincidan con los archivos o las clases, por lo que un mapeo de uno a uno con estos es ideal.

Debido a los gastos generales de Cucumber, y debido a que no obtenemos el valor de los beneficios que Cucumber proporciona a cambio de sus gastos generales, RSpec es un mejor ajuste para el comportamiento a nivel de unidad. (Esto también es cierto para JUnit, NUnit, etc.)

Si le falta el "Dado, Cuándo, Entonces" de Pepino, intente agregarlos como comentarios. Esto funciona bien para mi.

0

Las pruebas unitarias son para probar una unidad particular del código de forma aislada. La granularidad habitual es un método (o pocos métodos que interactúan) en una clase.

Las pruebas de integración se centran en probar muchas capas de la pila de aplicaciones. Por ejemplo, puede ejecutar una prueba de integración que verifique la interacción de su código con una base de datos. La mayoría de las pruebas de integración se centran en dos o tres capas de objetos.

Las pruebas de pepino en particular tienden a centrarse en la pila completa de aplicaciones, ya que ejercen la aplicación simulando un usuario real en la interfaz y todas las capas de la aplicación, desde la UI hasta los servicios de fondo (bases de datos, sistema de archivos , redes, etc.) están en su lugar y son utilizados.

En pocas palabras:

una unidad de prueba comprueba que una determinada pieza de código permanece a su contrato con el resto del mundo ...

Mientras que una prueba comprueba el pepino interacción de varias piezas de código (una porción vertical que algunas personas pueden decir), con la belleza adicional que la prueba en sí misma lee como inglés simple.

0

Según Aslak Hellesøy, Cucumber no es una herramienta de prueba, sino una herramienta de colaboración (para BDD).Recientemente se ha publicado sobre este aparente error:

https://cucumber.pro/blog/2014/03/03/the-worlds-most-misunderstood-collaboration-tool.html

Dicho esto, hay una gran cantidad de pruebas escritas por debajo del nivel de aceptación que caería alrededor de la capa de pruebas de integración. Es decir,

Given a user at 123 Evergreen Terrace 
When I lookup their name 
Then I get Homer Simpson 

en lugar de

Given an address 
When I lookup a name 
Then the home owner name is displayed 

No ayuda a que los programas de cukes.info como un ejemplo imprescindible (en lugar de declarativo).

Las pruebas de pepino se ejecutan lentamente en comparación con las pruebas unitarias Rspec o Test :: Unit o MiniTest. Tienen una gran sobrecarga (puede llevar minutos cargar el entorno, incluidas todas las clases de objetos de página, analizar los archivos de características y ejecutar pruebas). Ejecutar solo las pruebas de unidad de pepino sería más rápido que ejecutar pruebas equivalentes de integración, pero no tan rápido como ejecutar algo más ligero, como los tres mencionados anteriormente.

(estoy respondiendo a esta pregunta histórica, ya que fue uno de los primeros éxitos llegué en la búsqueda de alternativas a Pepino para las pruebas de integración)

Cuestiones relacionadas