# Reutiliza contenedores con suites de pruebas


En la sección anterior, viste cómo levantar un contenedor de Docker de Postgres para una sola prueba. Pero a menudo tienes múltiples pruebas en un solo archivo, y es posible que desees reutilizar el mismo contenedor de Docker de Postgres para todas ellas.

Puedes utilizar el paquete [testify suite](https://pkg.go.dev/github.com/stretchr/testify/suite) para implementar acciones comunes de configuración (setup) y desmontaje (teardown) de pruebas.

## Extrae la configuración del contenedor

Primero, extrae la lógica de creación de `PostgresContainer` en un archivo separado llamado `testhelpers/containers.go`:

```go
package testhelpers

import (
	"context"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/modules/postgres"
)

type PostgresContainer struct {
	*postgres.PostgresContainer
	ConnectionString string
}

func CreatePostgresContainer(t *testing.T, ctx context.Context) *PostgresContainer {
	t.Helper()

	ctr, err := postgres.Run(ctx,
		"postgres:16-alpine",
		postgres.WithInitScripts(filepath.Join("..", "testdata", "init-db.sql")),
		postgres.WithDatabase("test-db"),
		postgres.WithUsername("postgres"),
		postgres.WithPassword("postgres"),
		postgres.BasicWaitStrategies(),
	)
	testcontainers.CleanupContainer(t, ctr)
	require.NoError(t, err)

	connStr, err := ctr.ConnectionString(ctx, "sslmode=disable")
	require.NoError(t, err)

	return &PostgresContainer{
		PostgresContainer: ctr,
		ConnectionString:  connStr,
	}
}
```

En `containers.go`, `PostgresContainer` extiende el `PostgresContainer` de testcontainers-go para proporcionar un acceso fácil a `ConnectionString`. La función `CreatePostgresContainer()` acepta `*testing.T` como su primer parámetro, llama a `t.Helper()` para que los fallos de prueba apunten al llamador y utiliza `testcontainers.CleanupContainer()` para registrar la limpieza automática.

## Escribe la suite de pruebas

Crea `customer/repo_suite_test.go` e implementa pruebas para crear un cliente y obtener un cliente por correo electrónico utilizando el paquete testify suite:

```go
package customer

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"
	"github.com/testcontainers/testcontainers-go-demo/testhelpers"
)

type CustomerRepoTestSuite struct {
	suite.Suite
	pgContainer *testhelpers.PostgresContainer
	repository  *Repository
	ctx         context.Context
}

func (suite *CustomerRepoTestSuite) SetupSuite() {
	suite.ctx = context.Background()
	suite.pgContainer = testhelpers.CreatePostgresContainer(suite.T(), suite.ctx)

	repository, err := NewRepository(suite.ctx, suite.pgContainer.ConnectionString)
	require.NoError(suite.T(), err)
	suite.repository = repository
}

func (suite *CustomerRepoTestSuite) TestCreateCustomer() {
	t := suite.T()

	customer, err := suite.repository.CreateCustomer(suite.ctx, Customer{
		Name:  "Henry",
		Email: "henry@gmail.com",
	})
	require.NoError(t, err)
	assert.NotNil(t, customer.Id)
}

func (suite *CustomerRepoTestSuite) TestGetCustomerByEmail() {
	t := suite.T()

	customer, err := suite.repository.GetCustomerByEmail(suite.ctx, "john@gmail.com")
	require.NoError(t, err)
	assert.Equal(t, "John", customer.Name)
	assert.Equal(t, "john@gmail.com", customer.Email)
}

func TestCustomerRepoTestSuite(t *testing.T) {
	suite.Run(t, new(CustomerRepoTestSuite))
}
```

Esto es lo que hace el código:

- `CustomerRepoTestSuite` extiende `suite.Suite` e incluye campos compartidos en múltiples pruebas.
- `SetupSuite()` se ejecuta una vez antes de todas las pruebas. Llama a `CreatePostgresContainer(suite.T(), ...)` que gestiona el registro de la limpieza automáticamente mediante `CleanupContainer`, por lo que no es necesario un `TearDownSuite()`.
- `TestCreateCustomer()` utiliza `require.NoError()` para la operación de creación (falla de inmediato si hay un error) y `assert.NotNil()` para la verificación del ID.
- `TestGetCustomerByEmail()` utiliza `require.NoError()` y luego realiza aserciones sobre los valores devueltos.
- `TestCustomerRepoTestSuite(t *testing.T)` ejecuta la suite de pruebas cuando ejecutas `go test`.

> [!TIP]
> Para los propósitos de esta guía, las pruebas no restablecen los datos en la base de datos. En la práctica, es una buena idea restablecer la base de datos a un estado conocido antes de ejecutar cada prueba.

