4.2 Fixture 설계
Fixture는 test에 필요한 환경을 준비하고 use() 이후 정리합니다. Dependency graph에 따라 setup은 안쪽으로, teardown은 역순으로 실행됩니다.
import { test as base } from '@playwright/test';
type Fixtures = {
todoName: string;
};
export const test = base.extend<Fixtures>({
todoName: async ({}, use, testInfo) => {
const value = `todo-${testInfo.testId}`;
await use(value);
},
});
Test-scoped fixture는 test마다 준비되고 worker-scoped fixture는 worker process 수명 동안 공유됩니다. Backend account처럼 생성 비용이 큰 resource를 worker scope로 둘 수 있지만 worker 간 식별자를 분리합니다.
Fixture 기준
- Test가 무엇을 필요로 하는지 type으로 드러냅니다.
- Setup과 cleanup을 같은 fixture에 둡니다.
- 사용하지 않는 fixture는 lazy하게 실행되지 않도록 합니다.
- Scope를 넓힐수록 mutable state 공유를 줄입니다.
- Fixture 내부 failure에도 cleanup이 실행되도록
try/finally를 고려합니다.
큰 beforeEach에 모든 준비를 넣는 것보다 목적별 fixture를 조합하면 test가 읽기 쉽고 불필요한 setup을 줄일 수 있습니다.
참고: Fixtures
Scope 선택
type Fixtures = { todoPage: TodoPage };
type WorkerFixtures = { account: TestAccount };
export const test = base.extend<Fixtures, WorkerFixtures>({
account: [async ({}, use, workerInfo) => {
const account = await leaseAccount(workerInfo.workerIndex);
await use(account);
await releaseAccount(account);
}, { scope: 'worker' }],
todoPage: async ({ page }, use) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await use(todoPage);
},
});
Test fixture는 매 test마다 새 상태가 필요할 때, worker fixture는 생성 비용이 크고 worker 안에서 안전하게 공유할 수 있을 때 사용합니다.
Fixture dependency
Fixture는 parameter name으로 dependency graph를 구성합니다. Setup과 teardown은 dependency 순서를 따릅니다. 자동 fixture는 모든 test에 비용을 부과하므로 logging처럼 정말 전역인 경우에 제한합니다.
실습
todoPagefixture를 만들고 test body의 setup을 줄입니다.- 사용하지 않는 fixture가 실행되지 않는지 log로 확인합니다.
- Worker fixture failure가 어느 test에 영향을 주는지 report에서 봅니다.
- Teardown error가 assertion error를 가리지 않게 attachment를 남깁니다.