unit-testing - software - pruebas unitarias beneficios
Pruebas unitarias de separación y pruebas de integración en Go (3)
¿Existe una mejor práctica establecida para separar las pruebas unitarias y las pruebas de integración en GoLang (testificar)? Tengo una combinación de pruebas unitarias (que no dependen de ningún recurso externo y, por lo tanto, funcionan muy rápido) y pruebas de integración (que dependen de los recursos externos y, por lo tanto, se ejecutan más lentamente). Por lo tanto, quiero poder controlar si incluir o no las pruebas de integración cuando digo " go test
.
La técnica más directa parece ser definir una bandera de integración en main:
var runIntegrationTests = flag.Bool("integration", false
, "Run the integration tests (in addition to the unit tests)")
Y luego para agregar un enunciado if al principio de cada prueba de integración:
if !*runIntegrationTests {
this.T().Skip("To run this test, use: go test -integration")
}
¿Es esto lo mejor que puedo hacer? Busqué en la documentación del testimonio para ver si hay tal vez una convención de nombres o algo que logre esto para mí, pero no encontré nada. ¿Me estoy perdiendo de algo?
@ Ainar-G sugiere varios patrones geniales para separar las pruebas.
Este conjunto de prácticas de Go de SoundCloud recomienda usar etiquetas de compilación ( descritas en la sección "Restricciones de compilación" del paquete de compilación ) para seleccionar qué pruebas ejecutar:
Escribe un integration_test.go y dale una etiqueta de compilación de integración. Defina indicadores (globales) para cosas como direcciones de servicio y cadenas de conexión, y úselos en sus pruebas.
// +build integration var fooAddr = flag.String(...) func TestToo(t *testing.T) { f, err := foo.Connect(*fooAddr) // ... }
ir prueba toma etiquetas de compilación al igual que ir compilación, por lo que puede llamar
go test -tags=integration
. También sintetiza un paquete principal que llama a flag.Parse, por lo que las banderas declaradas y visibles se procesarán y estarán disponibles para sus pruebas.
Como una opción similar, también podría tener pruebas de integración ejecutadas de forma predeterminada mediante el uso de una condición de compilación // +build !unit
, y luego desactivarlas bajo demanda ejecutando go test -tags=unit
.
@adamc comenta:
Para cualquier otra persona que intente usar etiquetas de compilación, es importante que el // +build test
comentario de // +build test
sea la primera línea en su archivo, y que incluya una línea en blanco después del comentario; de lo contrario, el comando -tags
ignorará la directiva.
Además, la etiqueta utilizada en el comentario de compilación no puede tener un guión, aunque se permiten subrayados. Por ejemplo, // +build unit-tests
no funcionará, mientras que // +build unit_tests
hará.
Para explicar mi comentario a la excelente respuesta de @Ainar-G, en el último año he estado usando la combinación de -short
con la convención de nomenclatura de Integration
para lograr lo mejor de ambos mundos.
Unit and Integration prueba la armonía, en el mismo archivo
Construir banderas anteriormente me obligó a tener múltiples archivos ( services_test.go
, services_integration_test.go
, etc.).
En su lugar, tome este ejemplo a continuación donde los dos primeros son pruebas unitarias y tengo una prueba de integración al final:
package services
import "testing"
func TestServiceFunc(t *testing.T) {
t.Parallel()
...
}
func TestInvalidServiceFunc3(t *testing.T) {
t.Parallel()
...
}
func TestPostgresVersionIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
...
}
Tenga en cuenta que la última prueba tiene la convención de:
- usando
Integration
en el nombre de la prueba. - comprobando si se está ejecutando bajo la directiva
-short
flag.
Básicamente, la especificación dice: "escriba todas las pruebas normalmente. Si se trata de pruebas de larga duración o una prueba de integración, siga esta convención de nomenclatura y verifique que" -short
sea agradable para sus compañeros ".
Ejecutar solo pruebas unitarias:
go test -v -short
esto le proporciona un buen conjunto de mensajes como:
=== RUN TestPostgresVersionIntegration
--- SKIP: TestPostgresVersionIntegration (0.00s)
service_test.go:138: skipping integration test
Ejecute solo pruebas de integración:
go test -run Integration
Esto solo ejecuta las pruebas de integración. Útil para pruebas de humo de canarios en producción.
Obviamente, la desventaja de este enfoque es que si alguien ejecuta la go test
, sin el -short
, ejecutará por defecto todas las pruebas de prueba de unidad e integración.
En realidad, si su proyecto es lo suficientemente grande como para tener pruebas unitarias y de integración, entonces es muy probable que esté usando un Makefile
donde pueda tener directivas simples para usar go test -short
en él. O bien, simplemente README.md
en su archivo README.md
y README.md
el día.
Veo tres soluciones posibles. El primero es usar el modo corto para pruebas unitarias. Así que usaría go test -short
con pruebas unitarias y lo mismo pero sin el -short
para ejecutar también sus pruebas de integración. La biblioteca estándar usa el modo corto para omitir pruebas de larga ejecución o hacer que se ejecuten más rápido al proporcionar datos más simples.
El segundo es usar una convención y llamar a sus pruebas ya sea TestUnitFoo
o TestIntegrationFoo
y luego usar el -run
prueba de -run
para indicar qué pruebas ejecutar. Por lo tanto, debería utilizar la go test -run ''Unit''
para las pruebas unitarias e go test -run ''Integration''
para las pruebas de integración.
La tercera opción es usar una variable de entorno y obtenerla en la configuración de pruebas con os.Getenv
. Luego, usaría la go test
simple para las pruebas unitarias y FOO_TEST_INTEGRATION=true go test
para las pruebas de integración.
Yo personalmente preferiría la solución " -short
porque es más simple y se usa en la biblioteca estándar, por lo que parece que es una forma de hecho de separar / simplificar las pruebas de larga duración. Pero las soluciones -run
y os.Getenv
ofrecen más flexibilidad (se requiere más precaución también, ya que las expresiones regulares están involucradas con -run
).