what-the-compiler-lets-through 중앙값 2,096 → 2,590 자 seams-no-test-crosses → 3,091 자 bivariance 가 왜 느슨한 판정을 받는지, never 캐스트가 왜 아무것도 요구하지 않는지처럼 「이름을 댔으면 왜 있는지도 댄다」를 채웠다. 네 가지가 각각 무엇을 통과시키고 어디서 드러났는지를 표로 갈랐다. 검사 넷 중 무엇이 SQL 을 실제로 돌리는지도 표로 세웠다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.3 KiB
kind, slug, title, topic, topicName, project, status, lastVerifiedOn, sourceRevision, source
| kind | slug | title | topic | topicName | project | status | lastVerifiedOn | sourceRevision | source | ||
|---|---|---|---|---|---|---|---|---|---|---|---|
| CASE | the-composition-root-had-no-test | 합성 루트에 테스트가 없어 공개 사이트 전체가 오류 화면이었다 | seams-no-test-crosses | 테스트가 지나지 않는 이음매 | TechLog | 게시 전 | 2026-09-04 | tech-log@2026-09-02 |
|
합성 루트에 테스트가 없어 공개 사이트 전체가 오류 화면이었다
공개 사이트 전체가 오류 화면이었다. 로그아웃 상태 방문자 — 공개 사이트의 전체 독자 — 가 브라우저에서 요청을 한 건도 내보내지 못했다. 세 결함이 겹쳐 있었고 각각이 다음 것을 가렸다. 게이트웨이 테스트도 화면 테스트도 이 이음매를 지나지 않았다.
관계
- 이음매마다 그 이음매를 실제로 지나는 검사를 하나씩 둔다 합성 루트가 그 목록의 한 줄이다.
- 매퍼가 null 을 돌려주고 호출부가 걸러 내, 기록이 조용히 사라졌다 스텁 때문에 보이지 않던 다른 매핑 결함이다.
- 한 경계를 고쳤으면 값의 여정 끝에서 확인한다 이 사건이 그 규칙의 근거 하나다.
문제
공개 소스가 HTTP 어댑터로 바뀐 뒤 로그아웃 상태 방문자가 요청을 하나도 내보내지 못했다. 화면은 전부 오류였다.
이 경로는 그 주까지 브라우저에서 한 번도 돌지 않았다. 이전에는 정적 소스를 쓰고 있었다.
결론
세 결함이 겹쳐 있었고 앞의 것이 뒤의 것을 가리고 있었다.
1 : credential 을 붙이는 함수가 Studio 헬퍼에 먼저 묻고, 그 헬퍼가 자기 것이 아닌 프로파일에 null 을 준다. 아래 폴백이 세션을 읽고 인증되지 않은 것을 거절한다. 공개 읽기는 ANONYMOUS 프로파일이라 그 폴백으로 떨어졌다 2 : 봉투 오류 생성기가 오류 코드를 Studio enum 에 고정해 세 표면이 공유했다. 공개와 관리는 각자 자기 계약에 enum 을 선언하므로 그들이 돌려준 모든 오류가 검증에 실패해 계약 위반으로 도착했다 3 : not-found 경로가 봉투에 없는 필드를 읽고 있었다
엄격한 enum 을 잘못된 표면의 계약에 대고 검사해도 여전히 엄격해 보인다. 그래서 어떤 게이트도 잡지 못했다.
회귀 테스트가 실제 런타임 어댑터를 배포된 백엔드의 실제 404 본문에 대고 조립한다.
검증 환경
tech-log-frontend : 03986da · 7600711 공개 소스 : 정적 픽스처에서 HTTP 어댑터로 전환한 직후 확인 방식 : 실제 어댑터를 배포된 백엔드의 실제 404 본문에 대고 조립하는 회귀 테스트
재현 조건
- 로그아웃 상태로 공개 사이트를 연다
- 네트워크 탭에서 요청이 나가는지 본다
- 나가지 않으면 credential 을 붙이는 경로에서 어느 프로파일이 어떤 판정을 받는지 따라간다
본문
세 결함이 서로를 가렸다
공개 소스가 정적 픽스처에서 HTTP 어댑터로 바뀐 뒤 로그아웃 상태 방문자가 요청을 하나도 내보내지 못했다. 이 경로는 그 주까지 브라우저에서 한 번도 돌지 않았다.
첫 번째만 고쳤을 때 요청이 나가기 시작했고, 그러자 두 번째가 드러났다. 두 번째를 고치니 세 번째가 나왔다.
attachCredentials 가 Studio 헬퍼에 먼저 묻는데, 그 헬퍼는 자기 것이 아닌 프로파일에 null 을 돌려준다. 그 아래 폴백이 세션을 읽고 인증되지 않은 것을 거절한다. 공개 읽기는 익명 프로파일을 선언하므로 그 폴백에 떨어졌다 — 「이 프로파일은 내 것이 아니다」와 「이 요청은 인증되지 않았다」가 같은 null 로 표현되고 있었다.
요청이 흐르자 두 번째가 나왔다. envelopeError() 가 ApiError.code 를 Studio enum 에 고정해 세 표면이 공유했다. 공개와 관리는 각자 자기 계약에 enum 을 선언하므로 그들이 돌려준 모든 오류가 검증에 실패해 계약 위반으로 도착했다.
세 번째는 not-found 경로가 봉투에 없는 status 를 읽고 있던 것이다.
왜 어떤 게이트도 잡지 못했나
엄격한 enum 을 잘못된 표면의 계약에 대고 검사해도 여전히 엄격해 보인다.
검증은 돌고 있었고 통과하고 있었다. 대상이 틀렸을 뿐이다. 검증이 「값이 이 enum 에 있는가」를 묻는데 그 enum 이 다른 표면의 것이면, 물음은 성립하고 답만 늘 거짓이 된다.
스텁이 이음매를 덮지 않는다
이 결함은 공개 소스가 HTTP 가 된 뒤에야 나타날 수 있었다. 이번 주까지 그 경로는 브라우저에서 한 번도 돌지 않았다. 스위트가 잡지 못한 이유는 게이트웨이와 화면을 검사할 뿐 합성 루트의 credential 결정은 검사하지 않기 때문이다 — 그 이음매에는 테스트가 없고, 이것이 그 대가다.
게이트웨이 테스트는 실행기를 스텁으로 바꾸고 화면 테스트는 게이트웨이를 스텁으로 바꾼다. 둘 다 자기 층은 검사하지만 그 사이에서 credential 을 정하는 코드는 어느 쪽에도 들어가지 않는다.
같은 모양이 HTTP 매퍼에서도 났다
게시한 질문의 공개 상세가 「요청을 처리하지 못했습니다」만 띄웠다.
이 사고가 지나간 이유는 HTTP 게이트웨이의 질문 상세 매핑을 지나는 테스트가 없었기 때문이다. 화면 테스트는 정적 픽스처 어댑터를 쓰므로 계약 모양을 한 번도 통과시키지 않는다.
계약 모양 그대로의 응답을 진짜 게이트웨이에 넣고 네 칸이 채워져 나오는지 묻는 테스트를 넣었다. 되돌려 보면 운영에서 난 것과 같은 오류로 실패한다.
회귀 테스트가 무엇을 조립하나
이 이음매의 회귀 테스트는 실제 런타임 어댑터를 배포된 백엔드의 실제 404 본문에 대고 조립한다. 스텁을 하나도 쓰지 않으므로 credential 결정과 봉투 해석이 둘 다 실제로 돈다.
확인하지 못한 것
이 회귀 테스트가 덮는 것은 공개 읽기 프로파일이다. 다른 프로파일의 합성 루트에도 같은 구멍이 있는지는 세지 않았다.