tl; dr
En Pivotal escribimos Cedar porque usamos y amamos a Rspec en nuestros proyectos Ruby. Cedar no está destinado a reemplazar o competir con OCUnit; está destinado a brindar la posibilidad de pruebas de estilo BDD al Objetivo C, al igual que Rspec fue pionera en las pruebas de estilo BDD en Ruby, pero no ha eliminado Test :: Unit. Elegir uno u otro es en gran medida una cuestión de preferencias de estilo.
En algunos casos, diseñamos Cedar para superar algunas deficiencias en la forma en que OCUnit funciona para nosotros. Específicamente, queríamos poder usar el depurador en las pruebas, ejecutar pruebas desde la línea de comandos y en las compilaciones de CI, y obtener resultados de texto útiles de los resultados de las pruebas. Estas cosas pueden ser más o menos útiles para usted.
Respuesta larga
Decidir entre dos marcos de prueba como Cedar y OCUnit (por ejemplo) se reduce a dos cosas: estilo preferido y facilidad de uso. Comenzaré con el estilo, porque eso es simplemente una cuestión de opinión y preferencia; la facilidad de uso tiende a ser un conjunto de compensaciones.
Las consideraciones de estilo trascienden qué tecnología o lenguaje usa. Las pruebas unitarias de estilo xUnit han existido durante mucho más tiempo que las pruebas de estilo BDD, pero esta última ha ganado popularidad rápidamente, en gran parte debido a Rspec.
La principal ventaja de las pruebas de estilo xUnit es su simplicidad y su amplia adopción (entre los desarrolladores que escriben pruebas unitarias); Casi cualquier lenguaje en el que pueda considerar escribir código tiene un marco de estilo xUnit disponible.
Los marcos de estilo BDD tienden a tener dos diferencias principales en comparación con el estilo xUnit: cómo estructura la prueba (o las especificaciones) y la sintaxis para escribir sus afirmaciones. Para mí, la diferencia estructural es el principal diferenciador. Las pruebas xUnit son unidimensionales, con un método de configuración para todas las pruebas en una clase de prueba dada. Las clases que probamos, sin embargo, no son unidimensionales; a menudo necesitamos probar acciones en varios contextos diferentes, potencialmente conflictivos. Por ejemplo, considere una clase ShoppingCart simple, con un método addItem: (para los fines de esta respuesta, usaré la sintaxis Objective C). El comportamiento de este método puede diferir cuando el carrito está vacío en comparación con cuando el carrito contiene otros artículos; puede diferir si el usuario ha ingresado un código de descuento; puede diferir si el elemento especificado puede ' t ser enviado por el método de envío seleccionado; etc. Como estas posibles condiciones se cruzan entre sí, terminas con un número geométricamente creciente de contextos posibles; en las pruebas de estilo xUnit, esto a menudo conduce a muchos métodos con nombres como testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. La estructura de los marcos de estilo BDD le permite organizar estas condiciones de forma individual, lo que creo que hace que sea más fácil asegurarse de que cubra todos los casos, así como también es más fácil encontrar, cambiar o agregar condiciones individuales. Como ejemplo, usando la sintaxis de Cedar, el método anterior se vería así: en las pruebas de estilo xUnit, esto a menudo conduce a muchos métodos con nombres como testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. La estructura de los marcos de estilo BDD le permite organizar estas condiciones de forma individual, lo que creo que hace que sea más fácil asegurarse de que cubra todos los casos, así como también es más fácil encontrar, cambiar o agregar condiciones individuales. Como ejemplo, usando la sintaxis de Cedar, el método anterior se vería así: en las pruebas de estilo xUnit, esto a menudo conduce a muchos métodos con nombres como testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. La estructura de los marcos de estilo BDD le permite organizar estas condiciones de forma individual, lo que creo que hace que sea más fácil asegurarse de que cubra todos los casos, así como también es más fácil encontrar, cambiar o agregar condiciones individuales. Como ejemplo, usando la sintaxis de Cedar, el método anterior se vería así:
describe(@"ShoppingCart", ^{
describe(@"addItem:", ^{
describe(@"when the cart is empty", ^{
describe(@"with no discount code", ^{
describe(@"when the shipping method applies to the item", ^{
it(@"should add the item to the cart", ^{
...
});
it(@"should add the full price of the item to the overall price", ^{
...
});
});
describe(@"when the shipping method does not apply to the item", ^{
...
});
});
describe(@"with a discount code", ^{
...
});
});
describe(@"when the cart contains other items, ^{
...
});
});
});
En algunos casos, encontrará contextos que contienen los mismos conjuntos de afirmaciones, que puede SECAR utilizando contextos de ejemplo compartidos.
La segunda diferencia principal entre los marcos de estilo BDD y los marcos de estilo xUnit, la sintaxis de aserción (o "matcher"), simplemente hace que el estilo de las especificaciones sea algo más agradable; a algunas personas realmente les gusta, a otras no.
Eso lleva a la cuestión de la facilidad de uso. En este caso, cada marco tiene sus pros y sus contras:
OCUnit ha existido mucho más tiempo que Cedar, y está integrado directamente en Xcode. Esto significa que es sencillo crear un nuevo objetivo de prueba y, la mayoría de las veces, hacer que las pruebas funcionen "simplemente funciona". Por otro lado, descubrimos que en algunos casos, como ejecutarse en un dispositivo iOS, hacer que las pruebas de OCUnit funcionen era casi imposible. La configuración de las especificaciones de Cedar requiere más trabajo que las pruebas de OCUnit, ya que usted tiene la biblioteca y el enlace en sí mismo (nunca es una tarea trivial en Xcode). Estamos trabajando para facilitar la configuración, y cualquier sugerencia es más que bienvenida.
OCUnit ejecuta pruebas como parte de la compilación. Esto significa que no necesita ejecutar un ejecutable para ejecutar sus pruebas; Si alguna prueba falla, su compilación falla. Esto hace que el proceso de ejecutar pruebas sea un paso más simple, y la salida de prueba va directamente a la ventana de salida de compilación, lo que hace que sea fácil de ver. Elegimos que las especificaciones de Cedar se integren en un ejecutable que se ejecuta por separado por varias razones:
- Queríamos poder usar el depurador. Ejecuta las especificaciones de Cedar tal como lo haría con cualquier otro ejecutable, por lo que puede usar el depurador de la misma manera.
- Queríamos un inicio de sesión de consola fácil en las pruebas. Puede usar NSLog () en las pruebas de OCUnit, pero el resultado va a la ventana de compilación donde debe desplegar el paso de compilación para leerlo.
- Queríamos informes de prueba fáciles de leer, tanto en la línea de comandos como en Xcode. Los resultados de OCUnit aparecen muy bien en la ventana de compilación en Xcode, pero al compilar desde la línea de comandos (o como parte de un proceso de CI) se obtienen resultados de prueba entremezclados con muchos otros resultados de compilación. Con fases separadas de construcción y ejecución, Cedar separa la salida para que la salida de prueba sea fácil de encontrar. El corredor de prueba de Cedar predeterminado copia el estilo estándar de impresión "." para cada especificación que pasa, "F" para especificaciones que fallan, etc. Cedar también tiene la capacidad de usar objetos de reportero personalizados, por lo que puede obtener resultados de la forma que desee, con un poco de esfuerzo.
OCUnit es el marco oficial de pruebas unitarias para Objective C y es compatible con Apple. Apple tiene recursos básicamente ilimitados, por lo que si quieren que se haga algo, se hará. Y, después de todo, este es el sandbox de Apple en el que estamos jugando. Sin embargo, la otra cara de esa moneda es que Apple recibe del orden de miles de millones de solicitudes de asistencia e informes de errores cada día. Son notablemente buenos para manejarlos a todos, pero es posible que no puedan manejar los problemas que informa de inmediato, o en absoluto. Cedar es mucho más nuevo y menos horneado que OCUnit, pero si tiene preguntas o problemas o sugerencias, envíe un mensaje a la lista de correo de Cedar (cedar-discuss@googlegroups.com) y haremos lo que podamos para ayudarlo. Además, siéntase libre de bifurcar el código de Github (github.com/pivotal/cedar) y agregar lo que crea que falta.
Ejecutar pruebas OCUnit en dispositivos iOS puede ser difícil. Honestamente, no lo he intentado durante bastante tiempo, por lo que puede haber sido más fácil, pero la última vez que lo intenté simplemente no pude obtener pruebas de OCUnit para que ninguna funcionalidad UIKit funcione. Cuando escribimos Cedar nos aseguramos de que pudiéramos probar el código dependiente de UIKit tanto en el simulador como en los dispositivos.
Finalmente, escribimos Cedar para pruebas unitarias, lo que significa que no es realmente comparable con proyectos como UISpec. Ha pasado bastante tiempo desde que intenté usar UISpec, pero entendí que se centraba principalmente en conducir la UI mediante programación en un dispositivo iOS. Decidimos específicamente no intentar que Cedar admita este tipo de especificaciones, ya que Apple estaba (en ese momento) a punto de anunciar la automatización UIA.