¿Cuáles son algunas convenciones de nomenclatura populares para las pruebas unitarias? [cerrado]

204

General

  • Siga los mismos estándares para todas las pruebas.
  • Sea claro sobre cada estado de prueba.
  • Sea específico sobre el comportamiento esperado.

Ejemplos

1) MethodName_StateUnderTest_ExpectedBehavior

Public void Sum_NegativeNumberAs1stParam_ExceptionThrown() 

Public void Sum_NegativeNumberAs2ndParam_ExceptionThrown () 

Public void Sum_simpleValues_Calculated ()

Fuente: estándares de denominación para pruebas unitarias

2) Separar cada palabra por subrayado

Public void Sum_Negative_Number_As_1st_Param_Exception_Thrown() 

Public void Sum_Negative_Number_As_2nd_Param_Exception_Thrown () 

Public void Sum_Simple_Values_Calculated ()

Otro

  • Finalizar nombres de métodos con Test
  • Nombre de método de inicio con nombre de clase
picado
fuente

Respuestas:

94

Estoy bastante contigo en este hombre. Las convenciones de nomenclatura que ha utilizado son:

  • Claro sobre qué es cada estado de prueba.
  • Específico sobre el comportamiento esperado.

¿Qué más necesitas de un nombre de prueba?

Contrariamente a la respuesta de Ray, no creo que sea necesario el prefijo Test . Es un código de prueba, lo sabemos. Si necesita hacer esto para identificar el código, entonces tiene mayores problemas, su código de prueba no debe mezclarse con su código de producción.

En cuanto a la longitud y el uso del guión bajo, su código de prueba , ¿a quién diablos le importa? Solo usted y su equipo lo verán, siempre que sea legible y tenga claro lo que está haciendo la prueba, ¡continúe! :)

Dicho esto, todavía soy bastante nuevo en probar y bloguear mis aventuras con él :)

Rob Cooper
fuente
20
Ligera contradicción "siempre que sea legible y clara" y "a quién ... le importa". Bueno, a todos les importa cuando no es legible y claro, por eso es importante. :-)
David Victor
1
Un argumento adicional para el prefijo. Cuando busca un archivo en IDE, puede buscar fácilmente casos de prueba comenzando con Testy su nombre de clase. Si el nombre de la clase y el nombre de la clase de prueba son los mismos, siempre tendremos que hacer una pausa y leer la ruta de dos archivos
ESTE USUARIO NECESITA AYUDA el
@THISUSERNEEDSHELP Creo que su punto puede superarse fácilmente al tener una buena estructura de carpetas como src / libs & src / tests . Sé que algunos marcos de prueba de ejecución requieren un prefijo como prueba para la identificación del código de prueba, por lo que en esos casos no se evitará, pero por lo demás puede ser un prefijo repetitivo no obligatorio .
negrotico19
@ negrotico19 Estoy pensando en el caso como en IntelliJ cuando usted Search Everywhere(shift shift) o Find a Class By Name(CMD O). Tengo que es va a diferenciarse ya sea por la estructura de carpetas o la estructura del módulo, pero cuando buscamos algo, que ya sabemos lo que queremos buscar. Por ejemplo, si estoy buscando una prueba, quiero limitar mi búsqueda testy luego buscar el nombre, en lugar de buscar el nombre y luego filtrar la prueba manualmente por ojos. Es una pequeña distinción, pero es mucho más fácil "probar [nombre de clase]" y tener una sola ventana emergente y reducir la carga mental
ESTE USUARIO NECESITA AYUDA el
37

También vale la pena leerlo: Pruebas de unidades de estructuración

La estructura tiene una clase de prueba por clase que se está probando. Eso no es tan inusual. Pero lo que era inusual para mí era que tenía una clase anidada para cada método que se estaba probando.

p.ej

using Xunit;

public class TitleizerFacts
{
    public class TheTitleizerMethod
    {
        [Fact]
        public void NullName_ReturnsDefaultTitle()
        {
            // Test code
        }

        [Fact]
        public void Name_AppendsTitle()
        {
            // Test code
        }
    }

    public class TheKnightifyMethod
    {
        [Fact]
        public void NullName_ReturnsDefaultTitle()
        {
            // Test code
        }

        [Fact]
        public void MaleNames_AppendsSir()
        {
            // Test code
        }

        [Fact]
        public void FemaleNames_AppendsDame()
        {
            // Test code
        }
    }
}

Y aquí está el por qué:

Bueno, por un lado, es una buena manera de mantener las pruebas organizadas. Todas las pruebas (o hechos) para un método se agrupan. Por ejemplo, si usa el atajo CTRL + M, CTRL + O para colapsar los cuerpos de los métodos, puede escanear fácilmente sus pruebas y leerlas como una especificación para su código.

También me gusta este enfoque:

MethodName_StateUnderTest_ExpectedBehavior

Entonces tal vez ajustarse a:

StateUnderTest_ExpectedBehavior

Porque cada prueba ya estará en una clase anidada

Lucifer
fuente
2
Para aquellos que usan el corredor de prueba de Resharper en Visual Studio, corrigieron errores usando clases de prueba anidadas en 8.x. Desde entonces, esta se convirtió en mi estructura preferida con diferencia.
angularsen
¿Importa que el nombre se vuelva realmente largo con el enfoque MethodName_StateUnderTest_ExpectedBehavior? Tales como "InitializeApiConfiguration_MissingApiKey_IllegalArgumentException". ¿Es este realmente un buen nombre de prueba?
portfoliobuilder
28

Tiendo a usar la convención de MethodName_DoesWhat_WhenTheseConditionsmodo que, por ejemplo:

Sum_ThrowsException_WhenNegativeNumberAs1stParam

Sin embargo, lo que sí veo mucho es hacer que el nombre de la prueba siga la estructura de prueba unitaria de

  • Organizar
  • Actuar
  • Afirmar

Que también sigue la sintaxis BDD / Gherkin de:

  • Dado
  • Cuando
  • Luego

que sería nombrar la prueba de la siguiente manera: UnderTheseTestConditions_WhenIDoThis_ThenIGetThis

así que a tu ejemplo:

WhenNegativeNumberAs1stParam_Sum_ThrowsAnException

Sin embargo, prefiero poner primero el nombre del método que se está probando, porque luego las pruebas se pueden ordenar alfabéticamente o aparecer ordenadas alfabéticamente en el cuadro desplegable de miembros en VisStudio, y todas las pruebas para 1 método se agrupan.


En cualquier caso, me gusta separar las secciones principales del nombre de la prueba con guiones bajos, en lugar de cada palabra , porque creo que hace que sea más fácil de leer y entender el punto de la prueba.

En otras palabras, me gusta: Sum_ThrowsException_WhenNegativeNumberAs1stParammejor que Sum_Throws_Exception_When_Negative_Number_As_1st_Param.

CodingWithSpike
fuente
22

Sí nombro mis métodos de prueba como otros métodos que usan "PascalCasing" sin guiones bajos ni separadores. Dejo la prueba de postfix para el método, porque no agrega ningún valor. El atributo TestMethod indica que el método es un método de prueba .

[TestMethod]
public void CanCountAllItems() {
  // Test the total count of items in collection.
}

Debido al hecho de que cada clase de prueba solo debe probar otra clase, dejo el nombre de la clase fuera del nombre del método. El nombre de la clase que contiene los métodos de prueba se nombra como la clase bajo prueba con el postfix "Pruebas".

[TestClass]
public class SuperCollectionTests(){
    // Any test methods that test the class SuperCollection
}

Para los métodos que prueban excepciones o acciones que no son posibles, prefiero el método de prueba con la palabra No puedo .

[TestMethod]
[ExpectedException(typeOf(ArgumentException))]
public void CannotAddSameObjectAgain() {
  // Cannot add the same object again to the collection.
}

Mi convección de nomenclatura se basa en el artículo "Consejos TDD: Convenciones y pautas de nomenclatura de prueba" de Bryan Cook. Encontré este artículo muy útil.

Jehof
fuente
1
+1 para el enlace a mi publicación, aunque no es necesario usar un prefijo "Prueba" en sus Pruebas. Asegúrese de que sus pruebas especifiquen el comportamiento esperado. Por ejemplo, CanRetrieveProperCountWhenAddingMultipleItems ()
bryanbcook
2
No me gusta porque no incluye el comportamiento esperado
Johannes Rudolph
5

El primer conjunto de nombres es más legible para mí, ya que CamelCasing separa las palabras y las barras inferiores separan las partes del esquema de nombres.

También tiendo a incluir "Prueba" en alguna parte, ya sea en el nombre de la función o en el espacio de nombres o clase que lo encierra.

Frank Szczerba
fuente
2
@Frank methodName = camelCase MethodName = PascalCase
Metro Smurf
@ metro-smurf: distinción interesante, nunca escuché el término que utilizaba PascalCase, y lo he estado haciendo durante mucho tiempo. Solo veo el término PascalCase aparecer en los círculos de desarrolladores de Microsoft, ¿es eso lo que haces?
Frank Szczerba
Historia sobre Pascal Casing y Camel Casing (de: Brad Abrams - blogs.msdn.com/brada/archive/2004/02/03/67024.aspx ) ... "En el diseño inicial del Marco tuvimos cientos de horas de debate sobre el nombre del estilo. Para facilitar estos debates, acuñamos una serie de términos. Con Anders Heilsberg (el diseñador original de Turbo Pascal) un miembro clave del equipo de diseño, no es de extrañar que elegimos el término Pascal Casing para el estilo de la carcasa popularizado por el lenguaje de programación Pascal ".
Heliac
-3

Mientras sigas una sola práctica, realmente no importa. En general, escribo una prueba de unidad única para un método que cubre todas las variaciones de un método (tengo métodos simples;) y luego escribo conjuntos de pruebas más complejos para los métodos que lo requieren. Por lo tanto, mi estructura de nombres generalmente es de prueba (un remanente de JUnit 3).

Munger
fuente
-8

Uso un prefijo 'T' para espacios de nombres de prueba, clases y métodos.

Intento ser ordenado y crear carpetas que replican los espacios de nombres, luego creo una carpeta de pruebas o un proyecto separado para las pruebas y replicar la estructura de producción para las pruebas básicas:

AProj
   Objects
      AnObj
         AProp
   Misc
      Functions
         AFunc
   Tests
      TObjects
         TAnObj
            TAnObjsAreEqualUnderCondition
      TMisc
         TFunctions
            TFuncBehavesUnderCondition

Puedo ver fácilmente que algo es una prueba, sé exactamente a qué código original pertenece (si no puede resolverlo, entonces la prueba es demasiado complicada de todos modos).

Se parece a la convención de nomenclatura de interfaces (quiero decir, no se confunde con las cosas que comienzan con 'I', ni con 'T').

Es fácil compilar con o sin las pruebas.

De todos modos, es bueno en teoría y funciona bastante bien para proyectos pequeños.

usuario566399
fuente
3
Enfoque interesante Algunas personas pueden argumentar que el prefijo T entra en conflicto con la convención que usa en genéricos (por ejemplo, func (T1, T2, TResult)), pero personalmente no me importa siempre que haya un consenso dentro del equipo. Los nombres son cortos, lo que hace que las cosas sean más legibles también.
picado el
Demasiado húngaro (notación) para mí. Además, según el anuncio, el prefijo T se usa para parámetros de tipo genérico.
Danny Varod
Estoy de acuerdo, la notación húngara ha sido depricada y debido al conflicto con los parámetros estándar de tipo genérico, no veo una excepción que se aplique en este caso (como ocurre con las interfaces).
SonOfPirate