같은 API 테스트를 200번씩 작성하느라 지쳐 라이브러리를 만들었다.
Source: Dev.to

[](https://dev.to/techygarg)
몇 년 전, 나는 규모가 꽤 되는 REST API를 가진 프로젝트에서 작업하고 있었다. 통합 테스트는 있었지만, 유지보수가 고통스러웠다. 새로운 엔드포인트가 추가될 때마다 새로운 테스트 클래스, 또 다른 픽스처, HttpClient 설정, 응답 역직렬화, ID와 타임스탬프 같은 동적 필드에 대한 커스텀 매처가 필요했다. 테스트 자체는 괜찮았지만, 그 주변의 절차가 문제였다.
나는 계속 생각했다: 테스트에 들어가는 실제 정보는 아주 적다. 메서드, 경로, 입력값, 기대 출력 정도뿐이다. 나머지는 모두 같은 골격을 다시 쓰는 것에 불과하다. 만약 테스트가 바로 그 정보만을 담고, 다른 것은 전혀 없었다면 어떨까?
그것이 내가 만든 것이었다. ConfIT 은 .NET 라이브러리로, API 테스트를 YAML(또는 JSON을 선호한다면) 로 작성하면 라이브러리가 실행, 모크 설정, 응답 매칭, 테스트 간 변수 전달 등을 처리한다.
테스트 예시는 다음과 같다:
CreateUser:
tags: [smoke]
api:
request:
method: POST
path: /api/users
body:
name: Alice
email: alice@example.com
response:
statusCode: 201
matcher:
semantic:
id: isUuid
extract:
userId: $.body.id
GetUser:
api:
request:
method: GET
path: /api/users/{{userId}}
response:
statusCode: 200
body:
name: Alice
email: alice@example.com
matcher:
ignore: [createdAt]
Enter fullscreen mode
Exit fullscreen mode
첫 번째 응답에서 추출된 userId 가 {{userId}} 를 통해 자동으로 두 번째 요청에 흐른다. 흔히 쓰이는 경우에 대해 별도의 커스텀 프로세서 코드를 작성할 필요가 없다.
matcher 블록은 내가 대부분의 어설션 코드를 대체해 준다. ignore 는 diff에서 신경 쓰지 않을 필드를 제외하고, semantic 은 이름이 붙은 타입 어설션을 제공한다: isUuid, isIsoDate, isEmail, greaterThan(n), hasLength(n) 등. 매 프로젝트마다 손수 작성하던 것들을 자동화한다.
내가 일상에서 가장 많이 쓰는 점은 같은 YAML 파일이 두 수준에서 동작한다는 것이다. 컴포넌트 테스트에서는 서비스가 인‑프로세스로 부팅되고 의존성은 WireMock 으로 모킹된다. 통합 테스트에서는 모든 것이 실제다. 두 개의 테스트 스위트를 유지할 필요가 없다. 하나의 테스트 파일 세트를 유지하고 픽스처 설정만 바꾼다.
컴포넌트 스위트를 설정하던 예전 방식은 꽤 많은 보일러플레이트가 필요했다. 이제는 이렇게 간단하다:
public TestSuiteFixture() =>
_suite = SuiteBootstrapper.ForComponent("suite.config.yaml",
onStarted: svc =>
new DbInitializer(svc.GetRequiredService()).Seed());
public TestSuiteContext Context => _suite.Context;
Enter fullscreen mode
Exit fullscreen mode
인증, 모크 서버 URL, 폴더 경로, 테스트 필터 등은 모두 suite.config.yaml 에 정의한다. C# 에 남는 유일한 코드는 DB 시딩인데, 이는 실제 프로젝트마다 달라야 하기 때문이다.
최근에 이 라이브러리가 ThoughtWorks Tech Radar 의 Assess 링에 올라갔다. 글에서는 컴포넌트 테스트와 통합 테스트 사이의 중복을 줄여준다고 언급했는데, 바로 그 목적을 위해 만들었다.
예상치 못한 점 하나: YAML 파일이 테스트 실행 외에도 유용해졌다. 팀에 새로 합류한 엔지니어는 파일을 읽어 API가 실제로 무엇을 하는지 파악할 수 있다. QA 팀은 C# 코드를 건드리지 않고도 테스트 케이스를 추가할 수 있다. 코드 리뷰 시에는 로직이 아니라 데이터를 검토하게 된다.
모든 경우에 맞지는 않는다. 복잡한 상태 흐름이나 많은 조건 로직이 포함된 테스트는 일반 코드로 작성하는 것이 더 낫다. 모든 것을 대체하려는 것이 아니라, CRUD 스타일 API 테스트 대부분에 대해 테스트 클래스를 거의 작성하지 않아도 되게 만든다.
이 라이브러리는 .NET 9 및 .NET 10을 타깃으로 한다. 비 .NET 서비스(Go, Node, Python 등)를 테스트하고 싶다면 AppLauncher 모드가 있다. 셸 명령으로 프로세스를 부팅하고 HTTP 로 통신하므로, 동일한 테스트 파일을 그대로 사용할 수 있다.
코드와 문서: github.com/techygarg/ConfIT
NuGet: nuget.org/packages/ConfIT
질문이 있거나 테스트 스위트에서 비슷한 불편을 겪은 경험을 공유하고 싶다면 언제든지 알려 주세요.