Pregunta

Actualmente uso una convención simple para mis pruebas unitarias. Si tengo una clase llamada " EmployeeReader " ;, creo una clase de prueba llamada " EmployeeReader.Tests. Luego creo todas las pruebas para la clase en la clase de prueba con nombres como:

  • Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
  • Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception

y así sucesivamente.

Recientemente he estado leyendo sobre una diferentes tipos de convenciones de nomenclatura utilizado en BDD. Me gusta la legibilidad de este nombre, para terminar con una lista de pruebas algo así como:

  • When_Reading_Valid_Employee (accesorio)
    • Employee_Object_Is_Generated (método)
    • Employee_Has_Correct_ID (método)
  • When_Reading_Missing_Employee (accesorio)
    • An_Invalid_Employee_ID_Exception_Is_Thrown (método)

y así sucesivamente.

¿Alguien ha usado ambos estilos de nombres? ¿Puede proporcionar algún consejo, beneficios, inconvenientes, problemas, etc. para ayudarme a decidir si cambiarme o no para mi próximo proyecto?

¿Fue útil?

Solución

Su segundo ejemplo (tener un accesorio para cada "tarea" lógica, en lugar de uno para cada clase) tiene la ventaja de que puede tener diferentes lógicas SetUp y TearDown para cada tarea, simplificando así sus métodos de prueba individuales y haciéndolos más legible.

No necesita decidirse por uno u otro como estándar. Usamos una mezcla de ambos, dependiendo de cuántas tareas "diferentes" tenemos que probar para cada clase.

Otros consejos

La convención de nomenclatura que he estado usando es:

  

functionName_shouldDoThis_whenThisIsTheSituation

Por ejemplo, estos serían algunos nombres de prueba para la función 'pop' de una pila

  

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

     

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

Siento que el segundo es mejor porque hace que las pruebas de su unidad sean más legibles para los demás, ya que las líneas largas hacen que el código parezca más difícil de leer o que sea más difícil de leer. Si todavía siente que existe alguna ambigüedad en cuanto a lo que hace la prueba, puede agregar comentarios para aclarar esto.

Parte del razonamiento detrás de la segunda convención de nomenclatura a la que hace referencia es que está creando pruebas y especificaciones de comportamiento al mismo tiempo. Establece el contexto en el que suceden las cosas y lo que debería suceder en ese contexto. (En mi experiencia, las observaciones / métodos de prueba a menudo comienzan con " debería _, " para que obtenga un formato estándar '' When_the_invoicing_system_is_told_to_email_the_client, " " should_initiate_connection_to_mail_server ").

Hay herramientas que se reflejarán sobre los dispositivos de prueba y generarán una hoja de especificaciones HTML bien formateada, eliminando los guiones bajos. Termina con documentación legible por humanos que está sincronizada con el código real (siempre que mantenga su cobertura de prueba alta y precisa).

Dependiendo de la historia / característica / subsistema en el que esté trabajando, las partes interesadas que no sean programadores pueden mostrar y comprender estas especificaciones para su verificación y retroalimentación, que es el núcleo de Agile y BDD en particular. p>

Utilizo el segundo método, y realmente ayuda a describir lo que debe hacer su software. También uso clases anidadas para describir un contexto más detallado.

En esencia, las clases de prueba son contextos, que pueden anidarse, y los métodos son aserciones de una sola línea. Por ejemplo,

public class MyClassSpecification
{
    protected MyClass instance = new MyClass();

    public class When_foobar_is_42 : MyClassSpecification 
    {
        public When_foobar_is_42() {
            this.instance.SetFoobar( 42 ); 
        }

        public class GetAnswer : When_foobar_is_42
        {
            private Int32 result;

            public GetAnswer() {
                this.result = this.GetAnswer();
            }

            public void should_return_42() {
                Assert.AreEqual( 42, result );
            }
        }
    }
}

que me dará el siguiente resultado en mi corredor de prueba:

MyClassSpecification+When_foobar_is_42+GetAnswer
    should_return_42

He recorrido los dos caminos que describe en su pregunta, así como algunos otros ... Su primera alternativa es bastante sencilla y fácil de entender para la mayoría de las personas. Personalmente, me gusta más el estilo BDD (su segundo ejemplo) porque aísla diferentes contextos y agrupa observaciones sobre esos contextos. El único inconveniente real es que genera más código, por lo que comenzar a hacerlo se siente un poco más engorroso hasta que vea las pruebas ordenadas. Además, si utiliza la herencia para reutilizar la configuración del dispositivo, desea un testrunner que genere la cadena de herencia. Considere una clase " An_empty_stack " y desea reutilizarlo para luego hacer otra clase: " When_five_is_pushed_on: An_empty_stack " quieres eso como salida y no solo " When_five_is_pushed_on " ;. Si su testrunner no lo admite, sus pruebas contendrán información redundante como: "When_five_is_pushed_on_empty_stack: An_empty_stack " solo para que la salida sea agradable.

voto por llamar a la clase de caso de prueba: EmployeeReaderTestCase y llamar a los métodos () como http: // xunitpatterns. com / Organization.html y http://xunitpatterns.com/Organization. html # Test% 20Naming% 20Conventions

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