사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
테스트
Akan 앱의 테스트는 signal부터 시작합니다. signal 테스트는 UI를 다듬기 전에, 자동 생성된
fetch로 실제 비즈니스 흐름을 확인합니다.이 페이지에서 쓰는 말
용어설명
signal test
자동 생성된
fetch로 endpoint를 호출해, 실제로 떠 있는 테스트 서버에서 확인하는 테스트입니다.fixture
레코드나 로그인한 사용자처럼 테스트에 필요한 것을 준비해 주는 재사용 함수입니다.
agent
테스트용 사용자와, 그 사용자로 이미 로그인된
fetch를 한데 묶은 것입니다.파일은 항상 두 개
signal 테스트는 항상 두 파일로 나눕니다. 이 구분은 취향 문제가 아닙니다:
fixture
<model>.signal.spec.tssampleOf(cnst.XInput) 위에 만든 재사용 fixture입니다. fixture마다 반환 타입을 밝히고 assertion은 넣지 않으며, 다른 모듈이 이 파일에서 import해 씁니다.검증
<model>.signal.test.tsdescribe("<Model> Signal"), describe 스코프의 let fixture, beforeAll 하나, 이야기 순서대로 놓인 it 블록으로 이뤄집니다.- 두 파일 모두 대상 모듈 옆에 둡니다. 예를 들어
lib/article/에article.signal.spec.ts와article.signal.test.ts가 함께 있습니다. - fetch 하나로 흐름 전체를 확인합니다. 회원가입, 권한, 입력 검증, 상태 전이까지 모두 같은 fetch로 다룹니다.
순서
spec 파일: fixture 만들기
spec 파일은 agent와 샘플 데이터를 만듭니다. 돌려주는
fetch에는 모든 endpoint가 바로 붙어 있어서, 모델별 namespace 없이 agent.fetch.createArticle(...)처럼 부릅니다.akanjs/test 도우미설명
getOrSetupSignalTestFetch
테스트 서버의 로그인하지 않은
fetch를 돌려주며, 처음 부를 때 서버를 띄웁니다.sampleOf
constant 클래스의 모든 필드를 샘플 값으로 채우고, 기본값이 있는 필드는 그 기본값을 씁니다.
sample
이메일이나 정해진 길이의 문자열처럼 랜덤 값을 하나씩 만듭니다.
테스트 서버 설정을 바꾸며, 아래 test 파일 섹션에서 다룹니다.
1. agent 타입은 한 곳에서
agent 타입은
lib/user/user.signal.spec.ts 한 곳에서만 다시 export하고 타입을 맞춥니다. 이 파일이 공용 agent를 내 app의 fetch에 묶습니다:apps/myapp/lib/user/user.signal.spec.ts
- agent 타입은 여기서만 import합니다. 다른 spec과 test는
UserAgent와AdminAgent를 소유한 lib이 아니라../user/user.signal.spec에서 가져옵니다. - agent는 가입을 마친 사용자와 로그인된 fetch입니다.
getUserAgentWithPhone은{ user, fetch, accessToken, userInput }를 돌려주고,getUserAgentWithPassword는 이메일과 비밀번호로 같은 일을 합니다. - 한 파일에 사용자가 둘 필요하면
getUserAgentWithPassword()를 두 번 부릅니다. 부를 때마다 새 랜덤 이메일로 가입하지만,getUserAgentWithPhone()을 두 번 부르면 같은 전화번호로 다시 가입하려다 실패합니다.
2. 모델의 fixture
모델의 spec은 그 agent 위에 fixture를 쌓습니다. fixture마다 반환 타입을 밝힙니다:
apps/myapp/lib/article/article.signal.spec.ts
- 테스트에서 중요한 필드만 덮어씁니다.
sampleOf(...)를 펼친 뒤status: "draft"처럼 필드 하나만 바꿉니다. - guest fetch는 로그인하지 않은 상태입니다.
getOrSetupSignalTestFetch()가 돌려주는 기본fetch로 방문자를 흉내 냅니다.
test 파일: 검증 쓰기
assertion은 모두 test 파일에 둡니다. fixture는 describe 스코프의
let 변수라서, 각 it이 앞의 it이 남긴 상태에서 이어갑니다:apps/myapp/lib/article/article.signal.test.ts
beforeAll하나에서 등장인물을 준비합니다. agent는 한 번 만들어 모든it이 함께 씁니다.it블록은 이야기 순서대로 놓습니다. 만들고, 발행하고, 거절돼야 하는 호출을 시도하는 순서입니다.- 거절은
await expect(p).rejects.toThrow()로 확인합니다. guard가 호출을 막으면fetchpromise가 reject됩니다. - test 파일마다 빈 데이터베이스에서 시작합니다. 파일마다 테스트 서버가 따로 뜨므로 서로의 데이터를 보지 않습니다.
테스트 서버 설정 바꾸기
테스트 서버는 기본으로 메모리 안의 SQLite 데이터베이스를 씁니다. 설정을 바꾸려면 test 파일 맨 위에서
configureSignalTest를 부릅니다:apps/myapp/lib/article/article.signal.test.ts
storage"memory" | "tempFile"기본값 "memory"
tempFile은 SQLite를 메모리 대신 임시 파일에 두고, 실행이 끝나면 지웁니다.portnumber기본값 38080 + worker id
테스트 서버가 여는 포트입니다.
- fixture가 실행되기 전에 부릅니다. 테스트 서버가 이미 떴다면
configureSignalTest는 에러를 던집니다.
무엇을 테스트할까
signal 테스트 파일은 보통 다음 다섯 가지 동작을 확인합니다:
분류예시
정상 흐름
생성, 수정, 발행, 보관.
권한
게스트는 발행할 수 없고, 작성자는 수정할 수 있으며, 관리자는 삭제할 수 있습니다.
입력 검증
title 누락, 잘못된 날짜, 중복된
accountId.상태 전이
draft에서 published로, pending에서 approved로.외부 연동
파일 업로드, 결제 콜백, 메시지 발행.
실행 명령
테스트는 워크스페이스 루트에서
akan test로 실행합니다. 대상을 준비한 뒤 그 안에서 bun test --isolate를 실행합니다:Terminal
<target>app | lib | pkg
테스트할 app, lib, 패키지의 이름입니다. 예:
myapp, shared.--writeboolean기본값 true
false면 app 테스트를 돌리기 전에 생성 코드를 쓰지 않습니다.다른 데이터베이스 모드로 돌리기
signal 테스트는
single 모드로 돕니다. multiple이나 cluster로 돌리려면 모드와 그 모드가 쓰는 서비스를 알려 줍니다:Terminal
multiple에는AKAN_TEST_REDIS_URL이,cluster에는AKAN_TEST_POSTGRES_URL까지 필요합니다. test 파일마다 비운 Redis 데이터베이스와 자기만의 Postgres 스키마에서 시작하고, 스키마는 끝나면 지웁니다.- Postgres 사용자는 스키마와 role을 만들 수 있어야 합니다.
akan dbup --mode cluster가 띄우는 Postgres의 사용자는 그럴 수 있습니다. - 모드는
AKAN_TEST_DATABASE_MODE로만 정합니다. 셸에 남아 있는AKAN_DATABASE_MODE는 테스트에 닿지 않습니다.
어떤 명령을 쓸까
명령
signal 테스트
apps · libs
패키지 테스트
pkgs
쓰는 명령
akan test <target>
✓
✓
워크스페이스 루트에서 실행합니다.
--isolate를 대신 붙여 줍니다.bun test --isolate
✓
패키지 디렉터리 안에서는 괜찮지만, 이렇게 돌리면 signal 테스트가 자기 app을 찾지 못합니다.
쓰지 않는 명령
bun test
--isolate가 없으면 테스트 파일들이 전역 객체 하나를 같이 써서 서로를 망가뜨립니다.✓동작함동작하지 않음
Signal test target is not configured.는 signal 테스트를akan test없이 돌렸다는 뜻입니다.akan test <app-or-lib>로 다시 실행하세요.


bun test를 그냥 실행하지 마세요. --isolate가 없으면 모든 test 파일이 전역 객체 하나를 같이 써서, 파일 간 상태 오염으로 테스트 수십 개가 실패합니다. bunfig.toml의 [test] isolate는 적용되지 않고, 워크스페이스 루트에서 실행하면 하위 프로세스의 stdio 파이프까지 깨집니다.꿀팁
- 데이터는 되도록 signal로 만듭니다. 그래야 테스트가 앱과 같은 규칙을 따릅니다.
- spec에는 assertion을 두지 않습니다. assertion이 든 fixture는 다른 사람의 테스트를 실패시키는데, 그 이유가 그쪽 파일에는 보이지 않습니다.
it블록 하나에는 중요한 동작 하나만 확인합니다. 그래야 실패했을 때 무엇이 깨졌는지 바로 드러납니다.