Pregunta

Escribo pruebas unitarias mientras escribo API y funcionalidades centrales. Pero quiero ser el fanboy genial que come, duerme y respira TDD y BDD. ¿Cuál es la mejor manera de comenzar con TDD / BDD de la manera correcta? ¿Algún libro, recurso, marco, mejores prácticas?

Mi entorno es backend de Java con interfaz de Grails, integrado con varios servicios web externos y bases de datos.

¿Fue útil?

Solución

Un buen lugar para comenzar es leer blogs. Luego compre los libros de las personas que están blogueando. Algunos que recomiendo encarecidamente:

" Tío Bob " Martin y los chicos de Object Mentor: http://blog.objectmentor.com/

P.S. obtener el código de limpieza del libro de Bobs:

http://www.amazon.com/Clean-Code-Handbook-Software- Artesanía / dp / 0132350882

Mi amigo Tim Ottinger (antiguo amigo de Object Mentor) http://agileinaflash.blogspot.com/ http://agileotter.blogspot.com/

Los muchachos de Jetbrains: http://www.jbrains.ca/permalink/285

Sentí la necesidad de expandirme en esto, ya que todos los demás parecen solo querer darte su opinión sobre TDD y no ayudarte en tu búsqueda para convertirte en un Jedi-Ninja. El Michael Jordan de TDD es Kent Beck. Realmente escribió el libro sobre él:

http://www.amazon.com/Test-Driven-Development-Kent- Beck / dp / 0321146530

también bloguea en:

http://www.threeriversinstitute.org/blog/?p=29

otro " famoso " Los partidarios de TDD incluyen:

Todos son excelentes personas para seguir. También debe considerar asistir a algunas conferencias como Agile 2010 o Software Craftsmanship (este año se realizaron al mismo tiempo en Chicago)

Otros consejos

No me gusta cuando la gente dice " La práctica X nunca es mala; si no funciona, no lo estás haciendo bien. " Lo sentimos, tiene la misma sensación que cualquier otro dogma religioso demasiado celoso. No lo compro

Estoy de acuerdo con esas personas que dicen que la mejor solución que su tiempo y dinero pueden pagar debería ser el objetivo.

Cualquiera que se oponga a TDD no debe ser acusado automáticamente de ignorar la calidad. (& "; Entonces, ¿cuándo dejó de golpear a su esposa? &";) El hecho es que el software tiene errores, y el costo de eliminarlos debe sopesarse en función del beneficio.

Lo mismo es cierto en la fabricación. Las tolerancias en las dimensiones y los acabados en las superficies no son todas iguales, porque a veces una tolerancia cercana y un acabado en espejo no están garantizados.

Sí, escribo pruebas unitarias, aunque no con frecuencia antes de escribir la clase. He visto el efecto de las pruebas en el diseño. Mido y miro la cobertura del código. Si encuentro que mi cobertura no es aceptable, escribo más pruebas. Entiendo el beneficio de una red de seguridad de pruebas unitarias para refactorización. Sigo esas prácticas incluso cuando estoy trabajando solo, porque he experimentado los beneficios de primera mano. Lo entiendo.

Pero miraría con recelo a cualquier compañero de equipo que comenzó a molestarme por " pruebas de unidad de alimentación, sueño y respiración y TDD. "

  

Mi gerente dice que la única forma de obtener un ascenso es si puedo llevar al equipo a TDD / BDD.

¿Alguna vez pensaste que tal vez esto te hace sonar como un imbécil? ¿Has descubierto que tu molestia ha alejado al resto de tu equipo?

Esta respuesta podría perderme algunos puntos de reputación, pero tenía que decirlo.

Creo que un mejor enfoque sería practicarlo usted mismo y dejar que otros vean el beneficio. Predicar con el ejemplo. Será mucho más persuasivo que correr la boca.

Geez, Grails tiene una generación de pruebas incorporada. Si está trabajando en un equipo que usa Grails, ¿cuánto más se necesita vender?

Mejores prácticas en mi humilde opinión: Haz lo que sea práctico y no solo porque es un proceso. No olvide cuál es el objetivo de escribir aplicaciones, y en el mundo de los negocios, no es escribir pruebas. No me malinterpreten, tienen su lugar, pero ese no debería ser el objetivo.

Encuentre a alguien que haya estado haciendo TDD / BDD y empareje el programa con ellos.

Las métricas son, en mi humilde opinión, la mejor manera de llegar de aquí para allá. Haga un seguimiento de qué tan bien está cubierto su código, mantenga deltas de complejidad de código para cada confirmación, use corredores de prueba que vigilen su código para detectar cambios y vuelva a ejecutar constantemente las pruebas correspondientes. Nunca permita que las longitudes de prueba superen algunas líneas, para que todas sus herramientas funcionen bien. Y recomendaría una vez al mes, tomarse un día libre para ejecutar su código a través de un probador de mutaciones. Ese día debería dedicarse únicamente a escribir exámenes. Todo esto te traerá dolor si aún no estás haciendo un buen TDD. Aprende del dolor y en muy poco tiempo lo harás bien.

Y nunca pierda de vista para qué son las pruebas: para describir el comportamiento deseado. Son su especificación ejecutable. (Esta es también la razón por la que me gusta Cucumber ; ¡ahora puede hacer que su PHB escriba sus pruebas por usted! Bueno, tal vez no bastante bueno, pero está cerca!)

" PD: Mi gerente dice que la única forma de obtener un ascenso es si puedo llevar al equipo a TDD / BDD. "

La única forma realista de lograr que un equipo haga algo (sin matarte en el proceso) es demostrarles claramente que les beneficiará cambiar sus hábitos. En otras palabras, escriba el código. Mucho código. Toneladas de código. Y luego, cuando llegue el correo electrónico crucial que altera radicalmente la especificación, muéstreles que puede cambiar su código fácilmente con la refactorización y lo que es peor porque estaba preparado para ello con sus pruebas en su lugar. El bar era verde, hack hack hack, RED BAR !!!!, hack hack hack, green bar, vete a casa.

Lea el libro de Kent Becks sobre el diseño basado en pruebas. Comience con las pruebas y luego haga el código. ¡Obtenga un servidor de compilación en ejecución que EJECUTE LAS PRUEBAS! No necesita tenerlo para todo el equipo; hágalo usted mismo y MOSTRARLE que ayuda.

Predicar solo molesta a los nativos :)

He estado haciendo TDD durante un par de años, pero últimamente he comenzado a buscar más en la forma BDD de impulsar mi diseño y desarrollo. Los recursos que me ayudaron a comenzar a trabajar en BDD fueron, en primer lugar, el blog de Dan North (el "fundador" de BDD). Eche un vistazo a Presentación de BDD . También hay un Wiki 'oficial' de BDD en behaviour-driven.org con una buena publicación que vale la pena leer.

Lo único que encontré realmente difícil cuando comencé con BDD (y aún lo encuentro un poco difícil) es cómo formular esos escenarios para que sean adecuados para BDD. Scott Bellware es un hombre muy hábil en BDD (o en Context-Spesification como le gusta acuñarlo) y su artículo El desarrollo basado en el comportamiento en Code Magazine me ayudó mucho a comprender la forma de pensar de BDD y a formular historias de usuarios.

También recomendaría el screencast de TekPub Diseño impulsado por el comportamiento con Specflow de Rob Conery. Una gran introducción a BDD y a una herramienta (SpecFlow) muy adecuada para hacer BDD en C #.

En cuanto a los recursos TDD, ya hay muchas buenas recomendaciones aquí. Pero solo quiero señalar un par de libros que realmente puedo recomendar;

Para comenzar, realice las pruebas unitarias, luego lea sobre cómo hacerlo correctamente, enseñe a su equipo cómo TDD y póngalos a bordo, porque en mi experiencia nada es más importante que hacer pruebas unitarias con todo su equipo.

También necesitará un proceso de compilación adecuado: usar un servidor de compilación que compile su código y ejecute su test. Recomiendo usar TeamCity (gratis con limitaciones).

Aprender a corregir las buenas pruebas unitarias es la parte difícil: algunas de ellas las aprenderá usted mismo (siempre y cuando mantenga las pruebas unitarias) y el resto lo podrá aprender buscando en Internet.

Sabrás que has alcanzado tu objetivo cuando NO escribas pruebas unitarias, ya que parte del desarrollo te parecerá equivocado.

Recuerde, ágil significa que no está completamente agotado en ningún método en particular. Si está trabajando en algo donde los beneficios de TDD no valen la pena (como hacer ediciones de prueba y error en una interfaz Swing), entonces no use TDD.

No puedo ver que nadie haya expresado realmente que TDD no se trata de pruebas. TDD-ing trata de expresar el comportamiento esperado antes de hacer la pequeña modificación de cambio de comportamiento. Esto mejora enormemente el diseño y permite enfocar de una manera que nunca antes había experimentado. Obtiene pruebas que protegen sus futuras refactorizaciones y una cobertura del 90% de forma gratuita.

Para aprenderlo, sugeriría (resumir lo que otros han dicho y agregar uno propio):

  1. visite los blogs y lea los libros mencionados anteriormente
  2. emparejarse con alguien competente en TDD
  3. práctica

Practiqué el kata Bowling (ejercicio) solo unas 20 veces (unos 30 minutos cada una) antes de comenzar a ver la luz. Comenzó analizando la descripción del tío Bob sobre ella aquí . Hay una gran cantidad de katas en el sitio codingdojo.org que incluye soluciones y debates. ¡Pruébalos!

Para tomar una cita de Nike: SOLO HAZLO.

Segundo consejo: nunca confíes en la interfaz de otra persona. Siempre escriba, en el nivel de cada clase, en la interfaz que desea que exista; escriba un adaptador para la implementación real según sea necesario.

Además, me resulta útil evitar los valores de retorno en los métodos y pensar en el código en términos de transmisión de mensajes en lugar de llamadas a funciones.

YMMV.

Hace un año, tenía poca idea de cómo hacer TDD (pero realmente quería (qué frustrante)) y nunca había oído hablar de BDD ... ahora hago ambas cosas compulsivamente. He estado en un entorno de desarrollo .Net, no Java, pero incluso reemplacé el & "; F5 - Ejecutar &"; botón con una macro para ejecutar Cucumber (BDD) o MBUnit (TDD) dependiendo de si es una Característica / Escenario o Especificación. Sin depurador si es posible. $ 1 en el frasco si usa el depurador (BROMAS (más o menos)).

El proceso es muy asombroso. El marco que estamos usando adicionalmente es de The Oracle. He tenido la suerte de encontrarlo, y estoy absorbiendo información, y ese marco que él / nosotros usamos es MavenThought.

Todo comienza con BDD. Nuestro BDD es directamente encima de pepino encima de rubí de hierro.

Característica:

Escenario: ....    Dado que hago bla ...
   Cuando hago otra cosa ...    Entonces suceden cosas maravillosas ...

Escenario: ...

Y esa no es la prueba de la unidad en sí misma, sino que controla la característica, escenario por escenario y, a su vez, las especificaciones de la unidad (prueba). Entonces, comienza en un escenario, y con cada paso que necesita completar conduce su TDD.

Y el TDD que hemos estado usando es una especie de BDD de alguna manera, porque observamos los comportamientos que requiere el SUT (Sistema bajo prueba) y se especifica un comportamiento por especificación (clase & "; prueba " archivo).

Ejemplo:

Aquí está la especificación para un comportamiento: cuando se crea el sistema bajo prueba.

Hay una especificación más (archivo de clase C # When_blah_happens) para otro comportamiento cuando cambia una propiedad, pero que se separa en un archivo separado.

using MavenThought.Commons.Testing;
using SharpTestsEx;

namespace Price.Displacement.Module.Designer.Tests.Model.Observers
{
    /// <summary>
    /// Specification when diffuser observer is created
    /// </summary>
    [ConstructorSpecification]
    public class When_diffuser_observer_is_created
        : DiffuserObserverSpecification
    {
        /// <summary>
        /// Checks the diffuser injection
        /// </summary>
        [It]
        public void Should_return_the_injected_diffuser()
        {
            Sut.Diffuser.Should().Be.SameInstanceAs(this.ConcreteDiffuser);
        }
    }
}

Este es probablemente el comportamiento más simple para un SUT, porque en este caso cuando se crea, la propiedad del difusor debe ser la misma que el difusor inyectado. Tuve que usar un difusor de hormigón en lugar de un simulacro porque en este caso el difusor es un objeto de núcleo / dominio y no tiene notificación de propiedad para la interfaz. El 95% del tiempo nos referimos a todas nuestras dependencias como Dep (), en lugar de inyectar la cosa real.

A menudo tenemos más de un [It] should_do_xyz () y, a veces, un poco de configuración, como quizás hasta 10 líneas de stubbing. Este es solo un ejemplo muy simple sin GivenThat () o AndGivenThatAfterCreated () en esa especificación.

Para la configuración de cada especificación, generalmente solo necesitamos anular un par de métodos de la especificación:

GivenThat () == > esto sucede antes de que se cree el SUT.

CreatSut () == > Simulamos automáticamente la creación del sut con StructureMap y el 90% del tiempo nunca necesita anular esto, pero si el constructor inyecta un hormigón, debe anular esto.

AndGivenThatAfterCreated () = > esto sucede después de que se crea el SUT.

WhenIRun () = > a menos que sea una [Especificación del constructor], la usamos para ejecutar UNA línea de código que es el comportamiento que estamos especificando para el SUT

Además, si hay un comportamiento común de dos o más especificaciones del mismo SUT, lo trasladamos a la especificación básica.

Todo lo que tengo que hacer para ejecutar la especificación es resaltar su nombre, ejemplo " When_diffuser_observer_is_created " y presione F5, porque recuerde, para mí F5 ejecuta una tarea de Rake ya sea test: feature [tag] if Cucumber, o test: class [SUT]. Tiene sentido para mí porque cada vez que ejecuta el depurador está a la basura, no se crea ningún código (ah y cuesta $ 1 (broma)).

Esta es una forma muy, muy limpia de especificar el comportamiento con TDD y tener SUTs muy simples y especificaciones simples. Si intentas ser un codificador de vaquero y escribes el SUT de mierda con dependencias difíciles, etc., sentirás el dolor de intentar hacer TDD y hartarte / rendirte O morder la bala y hacerlo bien.

Y aquí está el SUT real. Nos pusimos un poco elegantes y usamos PostSharp para agregar propiedades, notificar cambios en el Diffusor, por lo tanto, el Post.Cast < > ;. Y de nuevo, es por eso que inyecté un Concreto en lugar de un Simulacro. De todos modos, como puede ver, el comportamiento que falta definido en otra especificación es cuando algo cambia en el Difusor.

using System.ComponentModel;
using MavenThought.Commons.Events;
using PostSharp;
using Price.Displacement.Core.Products;
using Price.Displacement.Domain;

namespace Price.Displacement.Desktop.Module.Designer.Model.Observers
{
    /// <summary>
    /// Implementation of current observer for the selected product
    /// </summary>
    public class DiffuserObserver : AbstractNotifyPropertyChanged, IDiffuserObserver
    {
        /// <summary>
        /// gets the diffuser
        /// </summary>
        public IDiffuser Diffuser { get; private set; }

        /// <summary>
        /// Initialize with a diffuser
        /// </summary>
        /// <param name="diffuser">The diffuser to observe</param>
        public void Initialize(IDiffuser diffuser)
        {
            this.Diffuser = diffuser;
            this.NotifyInterface().PropertyChanged += (x, e) => this.OnPropertyChanged(e.PropertyName);
        }

        /// <summary>
        /// Gets the notify interface to use
        /// </summary>
        /// <returns>The instance of notify property changed interface</returns>
        protected INotifyPropertyChanged NotifyInterface()
        {
            return Post.Cast<Diffuser, INotifyPropertyChanged>((Diffuser)Diffuser);
        }
    }
}

En conclusión, este estilo de desarrollo BDD / TDD es genial. Me llevó un año, pero soy un converso total como forma de vida. No habría aprendido esto por mi cuenta. Recogí todo de The Oracle http://orthocoders.com/ .

Pastilla roja o azul, la elección es suya.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top