2010-08-08 17 views
7

Me estoy acostumbrando a TDD, pero me he encontrado con un problema inesperado: me estoy cansando de la cobertura del código al 100%. Las pruebas son cada vez más tediosas de escribir que el código en sí, y no estoy seguro si lo estoy haciendo bien. Mi pregunta es: ¿Qué tipo de cosas se supone que debes probar, y qué tipo de cosas son exageradas?Manejo de TDD/fatiga de prueba unitaria

Por ejemplo, tengo una prueba de la siguiente manera, y no estoy seguro si es útil en absoluto. ¿Qué se supone que debo hacer para seguir con TDD pero no me canso de escribir pruebas?

describe 'PluginClass' 

    describe '.init(id, type, channels, version, additionalInfo, functionSource, isStub)' 

     it 'should return a Plugin object with correct fields' 

      // Create test sets 
      var testSets = new TestSets() 
      var pluginData = { 
       'id'    : null, 
       'type'    : null, 
       'channels'   : null, 
       'version'   : null, 
       'additionalInfo' : null, 
       'functionSource' : null, 
       'isStub'   : true 
      } 
      testSets.addSet({ 'pluginData' : pluginData }) 
      var pluginData = { 
       'id'    : "testPlugin1", 
       'type'    : "scanner", 
       'channels'   : ['channelA', 'channelB'], 
       'version'   : "1.0", 
       'additionalInfo' : {'test' : "testing"}, 
       'functionSource' : "function() {alert('hi')}", 
       'isStub'   : false 
      } 
      testSets.addSet({ 'pluginData' : pluginData }) 

      for (var t = 0; t < testSets.getSets().length; t ++) { 
       var aTestSet = testSets.getSet(t) 

       var plugin = new Plugin().init(aTestSet.pluginData.id, 
               aTestSet.pluginData.type, 
               aTestSet.pluginData.channels, 
               aTestSet.pluginData.version, 
               aTestSet.pluginData.additionalInfo, 
               aTestSet.pluginData.functionSource, 
               aTestSet.pluginData.isStub ) 

       plugin.getID().should.eql aTestSet.pluginData.id 
       plugin.getType().should.eql aTestSet.pluginData.type 
       plugin.getChannels().should.eql aTestSet.pluginData.channels 
       plugin.getVersion().should.eql aTestSet.pluginData.version 
       plugin.getAdditionalInfo().should.eql aTestSet.pluginData.additionalInfo 
       eval("fn = " + aTestSet.pluginData.functionSource) 
       JSON.stringify(plugin.getFunction()).should.eql JSON.stringify(fn) 
       plugin.getIsStub().should.eql aTestSet.pluginData.isStub 
      } 

     end 

    end 

end 
+0

IMO, esta es una prueba de aceptación. – Gutzofter

Respuesta

7

Sin duda la "prueba" anterior es excesiva en muchos aspectos. Es demasiado largo y complicado, difícil de leer y afirma demasiadas cosas. Difícilmente puedo imaginar cómo pudo surgir esto de un proceso de TDD. No es de extrañar que te canses de cosas como esta ...

Desarrollo basado en pruebas significa que debes ir en pequeños pasos, donde cada paso es una prueba separada, afirma solo una cosa, y no contiene absolutamente ninguna lógica (es decir, no for, if/else o similar ...). Por lo tanto, el código anterior resultaría en aproximadamente 4-6 métodos de prueba separados, que luego implementaría uno por uno. Primero afirme la inicialización correcta de la propiedad (con diferentes valores según sea necesario), luego asegúrese de que los métodos funcionen como se espera, y así sucesivamente ...

La métrica de cobertura del código no dice nada sobre sus pruebas, excepto que puede mostrar usted el código de producción que no es tocado por ninguna prueba en absoluto. Especialmente no le dice si el código tocado realmente se prueba (y no solo se toca ...). Eso depende solo de la calidad de sus pruebas. Por lo tanto, no tome la cobertura del código demasiado en serio, hay muchos casos donde una cobertura más baja con mejores pruebas es mucho más preferible ...

En suma: No es excesivo tener pruebas para casi todo (100% cobertura), pero ciertamente es un problema tener pruebas como en su ejemplo.

Te recomiendo revisar su práctica de pruebas TDD/unidad, The Art Of Unit Testing libro podría ser un buen recurso ...

HTH!
Thomas

+0

+1 por recomendar * The Art of Unit Testing * - es un gran libro que brinda buenos consejos. – Bevan

1

El objetivo de las pruebas unitarias debe ser probar las partes del código que probablemente contengan errores. Lograr una cobertura del 100% de la prueba no debe ser un objetivo, y AFAIK, TDD no lo menciona como un objetivo.

La creación de pruebas exhaustivas para el código que es poco probable que contenga errores importantes es una pérdida de tiempo tediosa tanto ahora como a medida que su sistema evoluciona. (En el futuro, las pruebas de unidad duplicadas es probable que sean una fuente de regresiones sin sentido en las mismas pruebas que acaba de perder el tiempo de una persona para encontrar y corregir.)

Por último, usted y su gestión debe utilizar siempre sentido común cuando aplicando alguna metodología de desarrollo a un proyecto. Ninguna metodología jamás inventada será perfecta para todos los problemas/proyectos. Parte de tu trabajo consiste en detectar las situaciones en las que la metodología no funciona de manera óptima ... y si es necesario, adaptarla o incluso abandonarla. Y en este caso, el hecho de que la forma en que usted/su proyecto está usando TDD lo está volviendo loco es un signo claro que algo no está bien.

+0

"100% de cobertura de prueba ... TDD no lo menciona como un objetivo". De hecho, en su forma religiosa TDD exige pruebas escritas antes de cualquier línea de código en vivo. De lo contrario, de acuerdo – KolA

+0

Lea esto: http://agiledata.org/essays/tdd.html#Misconceptions –

3

Una cosa que creo que la gente olvida es que con las pruebas unitarias automatizadas, sigue siendo una práctica de codificación.Es perfectamente aceptable configurar clases con plantillas/genéricas, clases base, clases de ayuda o cualquier otro patrón de desarrollo de software con el que esté familiarizado para realizar las pruebas de su unidad. SI Sientes que estás haciendo lo mismo una y otra vez, ¡probablemente lo estés haciendo! Es una señal de que su cerebro le está diciendo: "Hay una mejor manera".

Así que hazlo.

+1

muy cierto. generalmente esto es una señal de que hay algo mal en alguna parte. – obelix

0

Parece que estás

  • constructores de pruebas con asignación simple miembro. Esto es excesivo a menos que haya alguna lógica no trivial en el constructor. En cambio, confíe en esto para hacerse la prueba como parte de algunas otras pruebas en las que se usarían los miembros.
  • comparando igualdad entre 2 objetos de valor. Redefina/defina la comprobación de igualdad en el tipo/clase del complemento, anulando el método igual. por lo que plugin.should.eql expected_plugin debería ser la afirmación en solitario
  • , también considere usar objetos auxiliares para construir datos de prueba complejos.
1

Su prueba intentará verificar demasiadas cosas a la vez. Dividirlo en varias pruebas y refactorizar el código de prueba también (sí, los métodos de ayuda están permitidos).

Además, tengo la impresión de que el código bajo prueba también está haciendo demasiado. Desacople su código (refactor mediante el uso de la clase de extracción y el método de extracción, etc.) y pruebe cada parte del código de producción de forma aislada. Descubrirá que esas pruebas serán menos, más simples y más fáciles de leer y escribir.

0

La fatiga, la pereza y la apatía es nuestro instinto natural para evitar el trabajo sin sentido, como escribir pruebas triviales, que es probablemente el caso. Intenta detener las pruebas triviales de las pruebas unitarias y deberías sentirte mejor al instante.

Su prueba particular lejos de ser complicada. He participado como revisor de código en muchos proyectos con miles de pruebas de unidades e integración y todavía veo un proyecto donde las pruebas serían más fáciles de leer y comprender que el código real en vivo. legibilidad TDD, "prueba como documentación" y ese tipo de promesas simplemente no son ciertas. Es fácil de probar: intente aprender una nueva base de códigos leyendo solo pruebas o leyendo solo códigos en vivo. ¿Qué camino es más completo? El código en vivo correctamente diseñado proporciona una imagen completa y holística del componente, mientras que las pruebas son simplemente afirmaciones fragmentadas al respecto.

El único beneficio de las pruebas es automatización - alguna verificación adicional de su código que no tiene que hacer manualmente/eso no se puede hacer mediante compilación o análisis de código. Período. Y este beneficio tiene un costo significativo: redacción y mantenimiento de las pruebas, por lo tanto, elija cuidadosamente qué probar.