# Escribe pruebas con Testcontainers


Crearás un contenedor PostgreSQL utilizando Testcontainers y lo usarás para todas
las pruebas. Antes de cada prueba, eliminarás todos los registros de clientes para que las
pruebas se ejecuten con una base de datos limpia.

## Configura fixtures de pytest

Esta guía utiliza [fixtures de pytest](https://pytest.org/en/stable/how-to/fixtures.html)
para la lógica de inicialización (setup) y finalización (teardown). Un enfoque recomendado es utilizar
[finalizadores](https://pytest.org/en/stable/how-to/fixtures.html#adding-finalizers-directly)
para garantizar que la limpieza se ejecute incluso si la configuración inicial falla:

```python
@pytest.fixture
def setup(request):
    # código de configuración (setup)

    def cleanup():
        # código de finalización (teardown)

    request.addfinalizer(cleanup)
    return some_value
```

## Crea el archivo de prueba

Crea un archivo `tests/__init__.py` vacío para habilitar la
[detección automática (auto-discovery)](https://pytest.org/explanation/goodpractices.html#test-discovery) de pytest.

Luego crea `tests/test_customers.py` con las fixtures:

```python
import os
import pytest
from testcontainers.postgres import PostgresContainer

from customers import customers

postgres = PostgresContainer("postgres:16-alpine")


@pytest.fixture(scope="module", autouse=True)
def setup(request):
    postgres.start()

    def remove_container():
        postgres.stop()

    request.addfinalizer(remove_container)
    os.environ["DB_CONN"] = postgres.get_connection_url()
    os.environ["DB_HOST"] = postgres.get_container_host_ip()
    os.environ["DB_PORT"] = str(postgres.get_exposed_port(5432))
    os.environ["DB_USERNAME"] = postgres.username
    os.environ["DB_PASSWORD"] = postgres.password
    os.environ["DB_NAME"] = postgres.dbname
    customers.create_table()


@pytest.fixture(scope="function", autouse=True)
def setup_data():
    customers.delete_all_customers()
```

Esto es lo que hacen las fixtures:

- La fixture `setup` tiene `scope="module"`, por lo que se ejecuta una vez para
  todas las pruebas del archivo. Inicia un contenedor PostgreSQL, establece
  variables de entorno con los detalles de conexión y crea la tabla `customers`.
  Una función de limpieza detiene el contenedor después de que se completan todas las pruebas.
- La fixture `setup_data` tiene `scope="function"`, por lo que se ejecuta antes de cada
  prueba. Elimina todos los registros para dar a cada prueba una base de datos limpia.

## Escribe las pruebas

Añade las funciones de prueba al mismo archivo:

```python
def test_get_all_customers():
    customers.create_customer("Siva", "siva@gmail.com")
    customers.create_customer("James", "james@gmail.com")
    customers_list = customers.get_all_customers()
    assert len(customers_list) == 2


def test_get_customer_by_email():
    customers.create_customer("John", "john@gmail.com")
    customer = customers.get_customer_by_email("john@gmail.com")
    assert customer.name == "John"
    assert customer.email == "john@gmail.com"
```

- `test_get_all_customers()` inserta dos registros de clientes, obtiene todos
  los clientes y verifica la cantidad.
- `test_get_customer_by_email()` inserta un cliente, lo obtiene por correo electrónico
  y verifica los detalles.

Debido a que `setup_data` elimina todos los registros antes de cada prueba, las pruebas pueden
ejecutarse en cualquier orden.

