Pregunta

Estoy seguro de que la mayoría de ustedes están escribiendo un montón de pruebas automatizadas y que también se han topado con algunos de los errores más comunes cuando las pruebas unitarias.

Mi pregunta es: ¿usted sigue las normas de conducta para los exámenes de escritura con el fin de evitar problemas en el futuro?Para ser más específicos:¿Cuáles son los propiedades de buena unidad de pruebas o ¿cómo se escribe tus pruebas?

Independiente del idioma sugerencias son bienvenidas.

¿Fue útil?

Solución

Permítanme comenzar por el taponamiento de las fuentes - Pragmática de Pruebas unitarias en Java con JUnit (Hay una versión con C#-Nunit demasiado..pero tengo este..su agnóstico para la mayor parte.Se recomiendan).

Buena prueba debe ser UN VIAJE (El acronymn no es pegajoso suficiente - tengo una copia impresa de el cheatsheet en el libro que tenía que sacar para asegurarse de que tiene este derecho..)

  • Automático :La invocación de las pruebas, así como la comprobación de los resultados de PASA/FALLA debería ser automático
  • Exhaustiva:La cobertura;Aunque los errores tienden a agruparse alrededor de ciertas regiones en el código, asegúrese de que la prueba de todas las principales rutas y escenarios..Uso de herramientas de si usted debe saber probados regiones
  • Repetible:Las pruebas deben producir los mismos resultados cada vez..cada tiempo.Las pruebas no deben confiar en incontrolable params.
  • Independiente:Muy importante.
    • Las pruebas deben sólo prueba una cosa en un momento.Múltiples afirmaciones están bien, siempre y cuando todos ellos están probando una característica o comportamiento.Cuando un error en la prueba, se debe indicar la localización del problema.
    • Pruebas no debe confiar uno en el otro - Aislado.Suposiciones sobre la orden de ejecución de la prueba.Asegurar la 'borrón y cuenta nueva' antes de cada prueba con el programa de instalación/desmontaje adecuadamente
  • Profesional:En el largo plazo tendrá como mucho el código de la prueba como de la producción (si no más), por lo tanto, seguir la misma norma de diseño para el código de prueba.Bien factorizada de los métodos de las clases con la intención de revelar los nombres, No hay duplicación de pruebas con buenos nombres, etc.

  • Buenas pruebas también se ejecutan Rápido.cualquier prueba que se lleva más de la mitad de un segundo para correr..debe ser trabajados.El más largo es el conjunto de prueba se lleva a correr..con menos frecuencia se ejecutará.Los más cambios que el dev se trate de colarse entre carreras..si se rompe cualquier cosa..se necesitará más tiempo para averiguar lo que cambio fue el culpable.

Actualización 2010-08:

  • Legible :Esto puede ser considerado parte de los Profesionales - sin embargo no se puede enfatizar lo suficiente.Una prueba de fuego sería encontrar a alguien que no es parte de su equipo y pedirle a él/ella para averiguar el comportamiento bajo prueba dentro de un par de minutos.Las pruebas deben ser mantenidos como código de la producción, de modo que sea fácil de leer, incluso si se requiere un mayor esfuerzo.Las pruebas deben ser simétricas (seguir un patrón) y conciso (prueba de un comportamiento en un momento).El uso de una convención de nomenclatura coherente (por ejemplo,el TestDox estilo).Evitar la confusión de la prueba con "detalles incidentales"..convertido en un estilo minimalista.

Aparte de estos, la mayoría de los otros son las directrices que reducir en los bajos se benefician de trabajo:por ejemplo,"No código de prueba de que usted no posee" (por ejemplo,los archivos Dll de terceros).No probar getters y setters.Mantenga un ojo en el coste-beneficio o de un defecto de la probabilidad.

Otros consejos

  1. No escribir descomunal pruebas. Como la 'unidad' en 'la prueba de unidad" sugiere, hacer de cada uno, como atómica y aislado como sea posible.Si es necesario, crear las condiciones previas mediante simulacros de objetos, en lugar de volver a crear demasiado de el típico entorno de usuario de forma manual.
  2. No probar las cosas de que obviamente el trabajo. Evitar probar las clases de un proveedor de terceros, especialmente en el suministro de la core Api del framework de código en.E. g., no prueba la adición de un elemento a un proveedor de la clase Hashtable.
  3. Considere el uso de una herramienta de cobertura de código como NCover para ayudar a detectar casos de borde que todavía tienen que probar.
  4. Trate de escribir la prueba antes de la aplicación. Creo que de la prueba, ya que más de una especificación que su aplicación va a cumplir.Cf.también behavior-driven development, una más específicos de la rama de desarrollo guiado por pruebas.
  5. Ser coherente. Si sólo escribir las pruebas para algunos de su código, es muy poco útil.Si usted trabaja en un equipo, y todos o algunos de los otros no pruebas de escritura, no es muy útil.Convencer a ti mismo y todos los demás de la importancia (y ahorro de tiempo propiedades) de la prueba, o que no te preocupes.

La mayoría de las respuestas que aquí se parece a la dirección de la unidad de mejores prácticas de prueba en general (cuándo, dónde, por qué y para qué), en lugar de escribir las pruebas mismas (cómo).Dado que la pregunta parecía muy específico en el "cómo" de la parte, pensé en este post, tomada de una "bolsa" de la presentación que realicé en mi empresa.

Womp 5 Leyes de Pruebas de Redacción:


1.El uso a largo y descriptivo del método de prueba nombres.

   - Map_DefaultConstructorShouldCreateEmptyGisMap()
   - ShouldAlwaysDelegateXMLCorrectlyToTheCustomHandlers()
   - Dog_Object_Should_Eat_Homework_Object_When_Hungry()

2.Escriba las pruebas en un Organizar/Act/Assert estilo.

  • Mientras que esta estrategia organizativa ha sido alrededor por un tiempo y llamado muchas cosas, la introducción de la "AAA", acrónimo recientemente ha ha sido una gran manera de conseguir a través de este.Hacer todas las pruebas en consonancia con AAA estilo hace que sean fáciles de leer y mantener.

3.Proporcionar siempre un mensaje de error con el Afirma.

Assert.That(x == 2 && y == 2, "An incorrect number of begin/end element 
processing events was raised by the XElementSerializer");
  • Un simple pero gratificante práctica que se hace evidente en el corredor de la aplicación de lo que ha fallado.Si usted no provee un mensaje, normalmente le dan algo como "se Espera cierto, era falso" en su fallo de salida, lo que hace que usted tiene que ir a leer la prueba para averiguar lo que está mal.

4.Comentario la razón de la prueba – ¿cuál es el negocio de la asunción?

  /// A layer cannot be constructed with a null gisLayer, as every function 
  /// in the Layer class assumes that a valid gisLayer is present.
  [Test]
  public void ShouldNotAllowConstructionWithANullGisLayer()
  {
  }
  • Esto puede parecer obvio, pero esta la práctica va a proteger la integridad de las pruebas de las personas que no entender la razón detrás de la prueba en el primer lugar.He visto muchos las pruebas se hacen eliminado o modificado que estaban perfectamente bien, simplemente porque la persona no entiende el supuestos en que la prueba fue de la verificación.
  • Si la prueba es trivial o el método de la el nombre es lo suficientemente descriptiva, se puede ser permisible para salir de la comentario off.

5.Cada prueba debe siempre revertir el estado de cualquiera de los recursos que toca

  • El uso de burla, cuando sea posible, evitar el trato con los recursos reales.
  • La limpieza debe hacerse en la prueba nivel.Las pruebas no deben tener ninguna la dependencia de la orden de ejecución.

Mantener estos objetivos en mente (adaptado del libro xUnit Patrones de Prueba por Meszaros)

  • Las pruebas deben reducir el riesgo, no introducción.
  • Las pruebas deben ser fáciles de ejecutar.
  • Las pruebas deben ser fáciles de mantener como el sistema evoluciona alrededor de ellos

Algunas cosas para hacerlo más fácil:

  • Las pruebas deben no sólo a causa de una de las razones.
  • Las pruebas deben sólo prueba una cosa
  • Minimizar las dependencias de pruebas (no dependencias en las bases de datos, archivos, interfaz de usuario etc.)

No olvide que usted puede hacer integración dentro de la prueba con su xUnit marco demasiado pero mantener la integración dentro de los exámenes y pruebas de unidad separada

Las pruebas deben ser aisladas.Una prueba no debe depender de otra.Aún más, una prueba no debe depender de sistemas externos.En otras palabras, la prueba de su el código, no el código el código depende.Usted puede probar esas interacciones como parte de su integración o pruebas funcionales.

Algunas de las propiedades de la gran unidad de pruebas:

  • Cuando un error en la prueba, debe ser inmediatamente obvio donde reside el problema.Si usted tiene que utilizar el depurador para localizar el problema, su análisis no son granular suficiente.Tener exactamente una afirmación por la prueba de ayuda aquí.

  • Cuando refactorizar, ninguna de las pruebas debe fallar.

  • Las pruebas se deben ejecutar tan rápido que no dude en ponerse en ejecución.

  • Todas las pruebas deben pasar siempre;el no-determinista resultados.

  • La unidad de pruebas debe estar bien factores, como el código de producción.

@Alotor:Si usted está sugiriendo que una biblioteca debe de tener sólo la unidad de pruebas en su API externa, no estoy de acuerdo.Quiero pruebas unitarias para cada clase, incluyendo las clases que yo no exponer a personas externas.(Sin embargo, si siento la necesidad de escribir las pruebas para los métodos privados, entonces necesito para refactorizar.)


EDITAR:Hubo un comentario acerca de la duplicación causada por "una afirmación por prueba".Específicamente, si usted tiene algún código para configurar un escenario, y luego quiero hacer varias afirmaciones acerca de él, pero sólo tiene una afirmación por prueba, quizás la duplicación de la configuración a través de múltiples pruebas.

Yo no tomo ese enfoque.En su lugar, yo uso de aparatos de prueba por el escenario.Aquí está una áspera ejemplo:

[TestFixture]
public class StackTests
{
    [TestFixture]
    public class EmptyTests
    {
        Stack<int> _stack;

        [TestSetup]
        public void TestSetup()
        {
            _stack = new Stack<int>();
        }

        [TestMethod]
        [ExpectedException (typeof(Exception))]
        public void PopFails()
        {
            _stack.Pop();
        }

        [TestMethod]
        public void IsEmpty()
        {
            Assert(_stack.IsEmpty());
        }
    }

    [TestFixture]
    public class PushedOneTests
    {
        Stack<int> _stack;

        [TestSetup]
        public void TestSetup()
        {
            _stack = new Stack<int>();
            _stack.Push(7);
        }

        // Tests for one item on the stack...
    }
}

Lo que está después es la delimitación de los comportamientos de la clase bajo prueba.

  1. Verificación de comportamientos esperados.
  2. La verificación de los casos de error.
  3. Cobertura de todas las rutas de código dentro de la clase.
  4. El ejercicio de todas las funciones miembro dentro de la clase.

La intención fundamental es aumentar su confianza en el comportamiento de la clase.

Esto es especialmente útil cuando se busca en la refactorización de código.Martin Fowler tiene una interesante artículo con respecto a las pruebas más en su sitio web.

HTH.

saludos,

Rob

La prueba debe originalmente a fallar.Entonces usted debe escribir el código que les hace pasar, de lo contrario se corre el riesgo de escribir una prueba de que está pinchado y siempre pasa.

Me gusta el Derecho de BÍCEPS acrónimo de la citada Pragmática De La Unidad De Pruebas libro:

  • Derecho:Son los resultados derecho?
  • B:Son todos los boundary condiciones correcta?
  • Yo:Podemos comprobar yonverse relaciones?
  • C:Podemos cross-resultados de la verificación a través de otros medios?
  • E:Puede que nos de la fuerza eerror de condiciones a suceder?
  • P:Son pel rendimiento de las características dentro de los límites?

Personalmente creo que puede llegar muy lejos por la comprobación de que usted obtenga el derecho de resultados (1+1 debe devolver 2 además de la función), probando todas las condiciones de frontera se puede pensar (como el uso de dos números de los que la suma es mayor que el entero valor máximo en la función add) y obligando a las condiciones de error, tales como fallos en la red.

Bueno las pruebas deben ser de fácil mantenimiento.

Todavía no he descubierto cómo hacerlo para entornos complejos.

Todos los libros de texto que empiezan a salir despegadas como su base de código comienza a llegar a en los cientos de 1000 millones de líneas de código.

  • Equipo de interacciones explotar
  • número de casos de prueba explotar
  • las interacciones entre los componentes explota.
  • tiempo para construir todos los unittests convierte en una parte significativa del tiempo de construcción
  • un cambio de API pueden prolongarse a cientos de casos de prueba.Aunque el código de la producción el cambio fue fácil.
  • el número de eventos que se requiera a la secuencia de los procesos en el derecho del estado aumenta, lo que a su vez aumenta prueba de tiempo de ejecución.

La buena arquitectura puede controlar algunos de interacción de la explosión, pero, inevitablemente, como los sistemas se vuelven más complejos, la realización de pruebas automatizadas del sistema crece.

Esto es donde puede empezar a tener que lidiar con los trade-offs:

  • sólo la prueba de la API externa de lo contrario, la refactorización interna de los resultados significativos de prueba caso de renovación.
  • la instalación y desmontaje de cada prueba se vuelve más complicado como un encapsulado subsistema, se retiene más del estado.
  • noche de compilación y ejecución de pruebas automatizadas crece a horas.
  • el aumento de la compilación y la ejecución veces significa que los diseñadores no o no se ejecutan todas las pruebas
  • para reducir la prueba de los tiempos de ejecución de considerar la secuenciación de pruebas para tomar reducir configurar y desmontaje

Usted también tiene que decidir:

¿dónde almacena los casos de prueba en su base de código?

  • ¿cómo documentar los casos de prueba?
  • puede probar los accesorios de ser re-utilizado para guardar caso de prueba de mantenimiento?
  • ¿qué sucede cuando una noche de ejecución del caso de prueba falla?Que hace el triage?
  • ¿Cómo mantener el simulacro de objetos?Si usted tiene 20 módulos, todos ellos usando su propio sabor de una maqueta de la API de registro, el cambio de la API de ondas rápidamente.No sólo los casos de prueba cambio, pero el 20 de burlarse de los objetos de cambio.Los 20 módulos fueron escritos a lo largo de varios años por diferentes equipos.Su un clásico re-problemas de uso.
  • los individuos y sus equipos de entender el valor de las pruebas automatizadas que simplemente no les gusta lo que el otro equipo lo está haciendo.:-)

Podría seguir para siempre, pero mi punto es que:

Las pruebas deben ser de fácil mantenimiento.

He cubierto estos principios en Este artículo de MSDN Magazine que creo que es importante para cualquier desarrollador de leer.

La manera en que yo definir "bueno" en las pruebas unitarias, es si disponen de las siguientes tres propiedades:

  • Ellos son legibles (denominación, afirma, variables, longitud, complejidad..)
  • Son de fácil mantenimiento (no hay lógica, no más de lo especificado, basado en el estado, refactorizado..)
  • Ellos son dignos de confianza (prueba de lo correcto, aislado, sin pruebas de integración..)
  • La unidad de Pruebas sólo las pruebas de la API externa de su Unidad, no de la prueba de comportamiento interno.
  • Cada prueba de un TestCase debe probar uno (y sólo uno) método dentro de esta API.
    • Adicional a los Casos de Prueba deben ser incluidos para el fracaso de los casos.
  • Prueba de la cobertura de sus pruebas:Una vez que una unidad es probada, el 100% de las líneas dentro de esta unidad debe habían sido ejecutados.

Jay Campos tiene un montón de buenos consejos acerca de la escritura de la unidad de pruebas y no hay un post donde se resumen los más importantes consejos.Allí podrá leer que usted debe pensar críticamente acerca de su contexto y juzgar si el consejo es que vale la pena para usted.Usted recibe un montón de increíbles respuestas aquí, pero es hasta que usted decida que es lo mejor para su contexto.Trate de ellos y refactorización si huele mal para usted.

Saludos

Nunca asuma que un trivial 2 método de la línea de trabajo.La escritura rápida de la prueba de unidad es la única manera de prevenir la falta nula de la prueba, fuera de lugar el signo menos y/o sutil ámbito de error de morder, inevitablemente, cuando se tiene menos tiempo para tratar con él de ahora.

En la segunda el "VIAJE" de respuesta, excepto que las pruebas DEBEN confiar uno en el otro!!!

Por qué?

SECO - Dont Repeat Yourself - se aplica a las pruebas!Dependencias de pruebas puede ayudar a: 1) ahorrar tiempo de configuración, 2) guardar el accesorio de recursos, y 3) localización de las fallas.Por supuesto, dado que su marco de pruebas de apoyos de primera clase dependencias.De lo contrario, tengo que admitir, que son malos.

Seguimiento http://www.iam.unibe.ch/~scg/Investigación/JExample/

A menudo las pruebas de unidad se basa en el objeto mock o burlarse de datos.Me gusta escribir tres tipos de pruebas de unidad:

  • "transitoria" de la unidad de pruebas:ellos crean sus propios simulacros de objetos/datos y probar su funcionamiento con ella, sino que se destruyen todo y no dejar rastro (como no hay datos en una base de datos de prueba)
  • "persistente" de la prueba de unidad:que las funciones de prueba dentro de su código de creación de objetos/datos que se necesitan más funciones avanzadas más tarde en su propia unidad de prueba (evitando para aquellos función avanzada para recrear cada vez su propio conjunto de la maqueta de objetos/datos)
  • "persistente" basado en la unidad de pruebas:pruebas unitarias usando burlarse de los objetos/datos de los que ya hay (porque crean en otra unidad de sesión de prueba) por la persistencia de la unidad de pruebas.

El punto es evitar reproducir todo con el fin de ser capaz de probar todas las funciones.

  • Puedo ejecutar el tercer tipo muy a menudo porque todos los simulacros de objetos/datos ya están ahí.
  • Puedo ejecutar el segundo tipo cuando mi cambio de modelo.
  • Ejecuto el primero para comprobar de forma muy básica de las funciones de vez en cuando, para comprobar básicos de las regresiones.

Piense acerca de los 2 tipos de pruebas y tratarlos de forma diferente - pruebas funcionales y pruebas de rendimiento.

El uso de los diferentes insumos y las métricas para cada uno.Puede que necesite utilizar un software diferente para cada tipo de prueba.

Yo uso una prueba consistente de la convención de nomenclatura descrita por Roy Osherove de la Unidad de Prueba estándares de Nomenclatura Cada método en un caso de prueba de la clase tiene la siguiente nomenclatura estilo MethodUnderTest_Scenario_Expectedresult.

    La primera prueba de la sección nombre es el nombre del método en el sistema bajo prueba.
    El siguiente es el escenario específico que está siendo probado.
    Finalmente es el resultado de ese escenario.

Cada sección se utiliza la parte Superior del Camello Caso y está delimitada por un bajo puntaje.

He encontrado esta útil cuando ejecuto la prueba la prueba se agrupan por el nombre del método en la prueba.Y tienen un convenio que permite a otros desarrolladores a entender la prueba de la intención.

Yo también añadir parámetros para el nombre del Método si el método en la prueba de haber sobrecargado.

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