이전 게시물에서는 테스트 방법 전/후에 Postgres 데이터베이스를 생성/드롭하는 Pytest Fixture를 만들었습니다. 이 부분에서는 Pytest 팩토리 픽스처를 사용하여 픽스처를 더욱 유연하고 구성 가능하도록 개선하고 싶습니다.
예를 들어 테스트에서 모의할 데이터베이스가 두 개 이상인 경우
def test_create_user(test_db1, test_db2): ...
거의 두 개의 동일한 조명기를 만들어야 합니다.
TEST_DB_URL = "postgresql://localhost" TEST_DB1_NAME = "test_foo" TEST_DB2_NAME = "test_bar" @pytest.fixture def test_db1(): with psycopg.connect(TEST_DB_URL, autocommit=True) as conn: cur = conn.cursor() cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB1_NAME}" WITH (FORCE)') cur.execute(f'CREATE DATABASE "{TEST_DB1_NAME}"') with psycopg.connect(TEST_DB_URL, dbname=TEST_DB1_NAME) as conn: yield conn cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB1_NAME}" WITH (FORCE)') @pytest.fixture def test_db2(): with psycopg.connect(TEST_DB_URL, autocommit=True) as conn: cur = conn.cursor() cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB2_NAME}" WITH (FORCE)') cur.execute(f'CREATE DATABASE "{TEST_DB2_NAME}"') with psycopg.connect(TEST_DB_URL, dbname=TEST_DB2_NAME) as conn: yield conn cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB2_NAME}" WITH (FORCE)')
여기에서는 "정적" 고정 장치가 약간 제한됩니다. 약간의 차이만 있으면 거의 동일하게 필요한 경우 코드를 복제해야 합니다. 다행히 Pytest에는 공장을 고정 장치로 개념이 있습니다.
Factory Fixture는 또 다른 Fixture를 반환하는 Fixture입니다. 모든 Factory와 마찬가지로 함수이기 때문에 반환된 Fixture를 사용자 정의하기 위한 인수를 받아들일 수 있습니다. 관례적으로 make_test_db와 같이 make_* 접두사를 붙일 수 있습니다.
픽스처 팩토리 make_test_db에 대한 유일한 인수는 생성/삭제할 테스트 데이터베이스 이름입니다.
그러므로 make_test_db 팩토리 픽스처를 기반으로 두 개의 "특수" 픽스처를 만들어 보겠습니다.
사용 방법은 다음과 같습니다.
@pytest.fixture def test_db_foo(make_test_db): yield from make_test_db("test_foo") @pytest.fixture def test_db_bar(make_test_db): yield from make_test_db("test_bar")
수익률을 보셨나요? 생성기 내에서 데이터 흐름과 제어를 처리하는 방법에 따라 수율과 수율 사이에 주요 차이점이 있습니다.
Python에서는 yield와 Yield from이 모두 생성기 함수 내에서 사용되어 일련의 값을 생성합니다. 그러나
즉, 우리는 전문 고정 장치가 아닌 고정 장치 공장에서 "양보"하고 싶습니다. 따라서 여기서는 Yield from이 필요합니다.
원래 픽스처 생성/삭제 데이터베이스에 필요한 변경 사항은 실제로 코드를 내부 함수로 래핑하는 것 외에는 거의 없습니다.
@pytest.fixture def make_test_db(): def _(test_db_name: str): with psycopg.connect(TEST_DB_URL, autocommit=True) as conn: cur = conn.cursor() cur.execute(f'DROP DATABASE IF EXISTS "{test_db_name}" WITH (FORCE)') # type: ignore cur.execute(f'CREATE DATABASE "{test_db_name}"') # type: ignore with psycopg.connect(TEST_DB_URL, dbname=test_db_name) as conn: yield conn cur.execute(f'DROP DATABASE IF EXISTS "{test_db_name}" WITH (FORCE)') # type: ignore yield _
이전 부분에서는 방금 생성된 빈 데이터베이스에 Yoyo 마이그레이션을 적용하는 픽스쳐도 있었습니다. 또한 그다지 유연하지도 않았습니다. 동일한 작업을 수행하고 실제 코드를 내부 함수로 래핑해 보겠습니다.
이 경우 코드는 테스트 메서드에서 반환된 후 정리 작업을 수행할 필요가 없기 때문에(수익률 없음)
@pytest.fixture def make_yoyo(): """Applies Yoyo migrations to test DB.""" def _(test_db_name: str, migrations_dir: str): url = ( urlparse(TEST_DB_URL) . _replace(scheme="postgresql+psycopg") . _replace(path=test_db_name) .geturl() ) backend = get_backend(url) migrations = read_migrations(migrations_dir) if len(migrations) == 0: raise ValueError(f"No Yoyo migrations found in '{migrations_dir}'") with backend.lock(): backend.apply_migrations(backend.to_apply(migrations)) return _ @pytest.fixture def yoyo_foo(make_yoyo): migrations_dir = str(Path(__file__, "../../foo/migrations").resolve()) make_yoyo("test_foo", migrations_dir) @pytest.fixture def yoyo_bar(make_yoyo): migrations_dir = str(Path(__file__, "../../bar/migrations").resolve()) make_yoyo("test_bar", migrations_dir)
두 개의 데이터베이스가 필요하고 여기에 마이그레이션을 적용하는 테스트 방법:
from psycopg import Connection def test_get_new_users_since_last_run( test_db_foo: Connection, test_db_bar: Connection, yoyo_foo, yoyo_bar): test_db_foo.execute("...") ...
Pytest 방법에 대한 데이터베이스를 생성하고 삭제하는 자체 픽스처 팩토리를 구축하는 것은 실제로 Python 생성기와 연산자의 산출량/수익률을 연습하는 데 좋은 연습입니다.
이 기사가 귀하의 데이터베이스 테스트 스위트에 도움이 되었기를 바랍니다. 궁금한 점은 댓글로 남겨주시면 즐거운 코딩 되세요!
위 내용은 Pytest 및 PostgreSQL: 모든 테스트를 위한 새로운 데이터베이스(2부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!