Pruebas unitarias nombrando las mejores prácticas

¿Cuáles son las mejores prácticas para nombrar las clases de prueba de la unidad y los métodos de prueba?

Esto fue discutido en SO antes, en ¿Cuáles son algunas de las convenciones de nomenclatura populares para Pruebas Unitarias?

No sé si este es un enfoque muy bueno, pero actualmente en mis proyectos de prueba, tengo asignaciones uno a uno entre cada clase de producción y una clase de prueba, por ejemplo, Product y ProductTest .

En mis clases de prueba, tengo métodos con los nombres de los métodos que estoy probando, un guión bajo, y luego la situación y lo que espero que suceda, por ejemplo, Save_ShouldThrowExceptionWithNullName() .

Me gusta la estrategia de nombres de Roy Osherove , es la siguiente:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Tiene toda la información necesaria sobre el nombre del método y de una manera estructurada.

La unidad de trabajo puede ser tan pequeña como un solo método, una clase o tan grande como múltiples clases. Debería representar todas las cosas que se probarán en este caso de prueba y están bajo control.

Para las asambleas utilizo el final típico de .Tests , que creo que está bastante extendido y lo mismo para las clases (que finaliza con las Tests ):

[NameOfTheClassUnderTestTests]

Previamente utilicé Fixture como sufijo en lugar de Tests, pero creo que este último es más común, luego cambié la estrategia de nomenclatura.

Me gusta seguir el estándar de nomenclatura “Debería” para las pruebas al nombrar el dispositivo de prueba después de la unidad bajo prueba (es decir, la clase).

Para ilustrar (usando C # y NUnit):

 [TestFixture] public class BankAccountTests { [Test] public void Should_Increase_Balance_When_Deposit_Is_Made() { var bankAccount = new BankAccount(); bankAccount.Deposit(100); Assert.That(bankAccount.Balance, Is.EqualTo(100)); } } 

¿Por qué “debería” ?

Encuentro que obliga a los redactores de pruebas a nombrar la prueba con una oración como “Debería [estar en algún estado] [después / antes / cuando] [la acción se lleva a cabo]”

Sí, escribir “debería” en todas partes se vuelve un poco repetitivo, pero como dije, obliga a los escritores a pensar de la manera correcta (por lo que puede ser bueno para los novatos). Además, generalmente resulta en un nombre de prueba legible en inglés.

Actualización :

Me di cuenta de que Jimmy Bogard también es un fanático de “debería” e incluso tiene una biblioteca de prueba de unidades llamada Should .

Actualización (4 años después …)

Para los interesados, mi enfoque para nombrar pruebas ha evolucionado a lo largo de los años. Uno de los problemas con el patrón En caso de que describo más arriba no es fácil saber de un vistazo qué método está bajo prueba. Para OOP, creo que tiene más sentido comenzar el nombre de la prueba con el método bajo prueba. Para una clase bien diseñada, esto debería dar como resultado nombres de métodos de prueba legibles. Ahora uso un formato similar a _Should_When . Obviamente, dependiendo del contexto, es posible que desee sustituir los verbos Should / When por algo más apropiado. Ejemplo: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Me gusta este estilo de nombre:

 OrdersShouldBeCreated(); OrdersWithNoProductsShouldFail(); 

y así. Le deja muy claro a un no examinador cuál es el problema.

Kent Beck sugiere:

  • Un accesorio de prueba por ‘unidad’ (clase de su progtwig). Los accesorios de prueba son clases ellos mismos. El nombre del dispositivo de prueba debe ser:

     [name of your 'unit']Tests 
  • Los casos de prueba (los métodos de fijación de prueba) tienen nombres como:

     test[feature being tested] 

Por ejemplo, teniendo la siguiente clase:

 class Person { int calculateAge() { ... } // other methods and properties } 

Un accesorio de prueba sería:

 class PersonTests { testAgeCalculationWithNoBirthDate() { ... } // or testCalculateAge() { ... } } 

Nombres de Clase . Para los nombres de los dispositivos de prueba, encuentro que “Prueba” es bastante común en el lenguaje ubicuo de muchos dominios. Por ejemplo, en un dominio de ingeniería: StressTest , y en un dominio de cosméticos: SkinTest . Lamento no estar de acuerdo con Kent, pero usar “Prueba” en mis aparatos de prueba (¿ StressTestTest ?) Es confuso.

“Unidad” también se usa mucho en dominios. Por ejemplo, MeasurementUnit . ¿Una clase llamada MeasurementUnitTest una prueba de “Measurement” o “MeasurementUnit”?

Por lo tanto, me gusta usar el prefijo “Qa” para todas mis clases de prueba. Ej. QaSkinTest y QaMeasurementUnit . Nunca se confunde con objetos de dominio, y usar un prefijo en lugar de un sufijo significa que todos los dispositivos de prueba viven juntos visualmente (es útil si tiene falsificaciones u otras clases de soporte en su proyecto de prueba)

Espacios de nombres Trabajo en C # y mantengo mis clases de prueba en el mismo espacio de nombres que la clase que están evaluando. Es más conveniente que tener espacios de nombres de prueba separados. Por supuesto, las clases de prueba están en un proyecto diferente.

Nombres de métodos de prueba . Me gusta nombrar mis métodos WhenXXX_ExpectYYY. Hace que la precondición sea clara y ayuda con la documentación automatizada (a la TestDox). Esto es similar al consejo en el blog de pruebas de Google, pero con más separación de precondiciones y expectativas. Por ejemplo:

 WhenDivisorIsNonZero_ExpectDivisionResult WhenDivisorIsZero_ExpectError WhenInventoryIsBelowOrderQty_ExpectBackOrder WhenInventoryIsAboveOrderQty_ExpectReducedInventory 

Ver: http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html

Para los nombres de los métodos de prueba, personalmente encuentro que el uso de nombres detallados y auto-documentados es muy útil (junto con los comentarios de Javadoc que explican mejor lo que está haciendo la prueba).

Hace poco presenté la siguiente convención para nombrar mis pruebas, sus clases y contener proyectos para maximizar sus descripciones:

Digamos que estoy probando la clase de Configuraciones en un proyecto en el espacio de nombres MyApp.Serialization .

Primero crearé un proyecto de prueba con el espacio de nombres MyApp.Serialization.Tests .

Dentro de este proyecto y, por supuesto, el espacio de nombres, crearé una clase llamada IfSettings (guardada como IfSettings.cs).

Digamos que estoy probando el método SaveStrings () . -> Voy a nombrar la prueba CanSaveStrings () .

Cuando ejecute esta prueba, mostrará el siguiente encabezado:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Creo que esto me dice muy bien, qué está probando.

Por supuesto, es útil que en inglés el sustantivo “Tests” sea el mismo que el verbo “tests”.

No hay límite para tu creatividad al nombrar las pruebas, de modo que obtenemos encabezados de oración completos para ellas.

Por lo general, los nombres de prueba tendrán que comenzar con un verbo.

Ejemplos incluyen:

  • Detecta (por ejemplo, DetectsInvalidUserInput)
  • Lanzamientos (por ejemplo, ThrowsOnNotFound)
  • Will (por ejemplo, WillCloseTheDatabaseAfterTheTransaction)

etc.

Otra opción es usar “eso” en lugar de “si”.

Este último me ahorra las pulsaciones de teclas y describe más exactamente lo que estoy haciendo, ya que no sé, que el comportamiento probado está presente, pero estoy probando si es así.

[ Editar ]

Después de usar la convención de nombres anterior durante un poco más de tiempo, he descubierto que el prefijo If puede ser confuso cuando se trabaja con interfaces. Sucede que la clase de prueba IfSerializer.cs parece muy similar a la interfaz ISerializer.cs en la “pestaña Abrir archivos”. Esto puede ser muy molesto cuando se cambian entre las pruebas, la clase que se está probando y su interfaz. Como resultado, ahora elegiría That over If como prefijo.

Además, ahora utilizo – solo para los métodos en mis clases de prueba, ya que no se considera la mejor práctica en ningún otro lugar – el “_” para separar las palabras en los nombres de mi método de prueba como en:

  • [Test] public void detecta_invalid_User_Input () *

Encuentro que esto es más fácil de leer.

[ Fin Editar ]

Espero que esto genere algunas ideas más, ya que considero que nombrar las pruebas es de gran importancia, ya que puede ahorrarle mucho tiempo que de otro modo se habría pasado intentando comprender lo que están haciendo las pruebas (por ejemplo, después de reanudar un proyecto después de una pausa prolongada) .

Yo uso el concepto de Darse-Cuando-Entonces . Eche un vistazo a este breve artículo http://cakebaker.42dh.com/2009/05/28/given-when-then/ . El artículo describe este concepto en términos de BDD, pero también se puede usar en TDD sin ningún cambio.

Creo que una de las cosas más importantes es ser coherente en su convención de nombres (y acordarlo con otros miembros de su equipo). A muchas veces veo muchas convenciones diferentes usadas en el mismo proyecto.

En VS + NUnit normalmente creo carpetas en mi proyecto para agrupar las pruebas funcionales. Luego creo las clases de dispositivos de prueba de unidades y los nombro después del tipo de funcionalidad que estoy probando. Los métodos [Test] se nombran a lo largo de las líneas de Can_add_user_to_domain :

 - MyUnitTestProject + FTPServerTests < - Folder + UserManagerTests <- Test Fixture Class - Can_add_user_to_domain <- Test methods - Can_delete_user_from_domain - Can_reset_password 

Debo agregar que mantener sus pruebas en el mismo paquete pero en un directorio paralelo a la fuente que se está probando elimina la saturación del código una vez que esté listo para implementarlo sin tener que hacer un montón de patrones de exclusión.

Personalmente me gustan las mejores prácticas descritas en “JUnit Pocket Guide” … ¡es difícil superar un libro escrito por el coautor de JUnit!

el nombre del caso de prueba para la clase Foo debe ser FooTestCase o algo así (FooIntegrationTestCase o FooAcceptanceTestCase), ya que es un caso de prueba. ver http://xunitpatterns.com/ para algunas convenciones de nomenclatura estándar como prueba, caso de prueba, accesorio de prueba, método de prueba, etc.