2026년 08월 31일

Postman·Bruno 환경 변수 자동화로 API 테스트 생산성 높이기

API 개발을 하다 보면 같은 토큰을 여러 요청에 일일이 붙여 넣거나, 스테이징 환경과 프로덕션 환경을 오갈 때마다 Base URL을 하나씩 수정하는 상황이 반복된다. 이런 작업은 실수를 유발하고 시간을 낭비한다. Postman과 Bruno 모두 환경 변수(Environment Variable) 기능을 제공하는데, 이를 스크립트와 함께 제대로 활용하면 반복 작업을 거의 없앨 수 있다.

환경 변수가 필요한 이유

API 테스트 도구를 처음 쓸 때는 요청마다 직접 값을 입력하는 방식으로 시작한다. 토큰 하나, URL 하나를 그때그때 붙여 넣는 것이 당장은 편해 보인다. 하지만 요청이 수십 개를 넘고, 개발·스테이징·프로덕션 환경을 동시에 관리해야 하는 시점이 오면 이야기가 달라진다.

토큰이 만료될 때마다 수십 개 요청을 열어 교체하거나, Base URL이 바뀔 때 컬렉션 전체를 뒤지는 일이 생긴다. 환경 변수는 이 문제를 해결하는 가장 직관적인 방법이다. 변수 하나를 바꾸면 그 변수를 참조하는 모든 요청이 동시에 업데이트된다.

Postman 환경 변수 설정과 자동화

환경 만들기와 변수 선언

Postman에서는 상단 우측의 환경 드롭다운에서 새 환경을 만들 수 있다. 환경별로 base_url, access_token, user_id 같은 변수를 선언하고 초기값(Initial Value)과 현재값(Current Value)을 각각 설정한다.

  • Initial Value: 팀원과 공유되는 값. 민감 정보는 넣지 않는다.
  • Current Value: 로컬에서만 사용되는 실제 값. .gitignore처럼 외부로 노출되지 않는다.

요청의 URL, 헤더, Body에서는 {{base_url}}, {{access_token}} 형태로 변수를 참조한다. 환경을 Development에서 Staging으로 바꾸는 것만으로 모든 요청의 대상 서버가 전환된다.

Pre-request Script로 토큰 자동 갱신

Postman의 진가는 스크립트 자동화에서 나온다. 컬렉션 레벨의 Pre-request Script에 토큰 발급 로직을 넣으면, 모든 요청이 실행되기 전에 토큰 상태를 확인하고 필요할 때만 갱신한다.

const tokenExpiry = pm.environment.get('token_expiry');
const now = Date.now();

if (!tokenExpiry || now >= parseInt(tokenExpiry)) {
  pm.sendRequest({
    url: pm.environment.get('base_url') + '/auth/token',
    method: 'POST',
    header: { 'Content-Type': 'application/json' },
    body: {
      mode: 'raw',
      raw: JSON.stringify({
        client_id: pm.environment.get('client_id'),
        client_secret: pm.environment.get('client_secret')
      })
    }
  }, (err, res) => {
    if (!err) {
      const body = res.json();
      pm.environment.set('access_token', body.access_token);
      pm.environment.set('token_expiry', now + body.expires_in * 1000);
    }
  });
}

이 스크립트는 token_expiry 시간을 확인해서 만료된 경우에만 인증 요청을 보내고, 응답으로 받은 토큰과 만료 시각을 환경 변수에 자동 저장한다. 이후 요청에서 {{access_token}}을 헤더에 참조하면 별도 조작 없이 항상 유효한 토큰이 사용된다.

Tests 탭으로 응답값 변수화

로그인 API 응답에서 받은 user_id나 session_token을 다음 요청에서 써야 할 때가 많다. Postman의 Tests 탭에 아래와 같이 작성하면 응답값을 환경 변수로 즉시 저장할 수 있다.

const res = pm.response.json();
pm.environment.set('user_id', res.data.id);
pm.environment.set('session_token', res.data.token);

이후 요청에서 {{user_id}}를 URL 경로에, {{session_token}}을 헤더에 쓰면 앞 요청 결과가 자동으로 이어진다. 회원 생성 → 프로필 조회 → 권한 수정 같은 흐름을 컬렉션 Runner로 연속 실행할 때 특히 유용하다.

Bruno 환경 변수 설정과 자동화

Bruno의 특징과 환경 파일 구조

Bruno는 Postman의 클라우드 의존성을 피하고 싶은 개발자들이 선택하는 오픈소스 API 클라이언트다. 컬렉션 전체가 로컬 파일로 저장되어 Git으로 버전 관리가 가능하다는 점이 가장 큰 차별점이다.

Bruno의 환경 설정은 컬렉션 폴더 안에 environments/ 디렉터리를 만들고 .bru 확장자의 환경 파일로 관리한다.

my-api/
├── environments/
│   ├── development.bru
│   ├── staging.bru
│   └── production.bru
├── auth/
│   └── login.bru
└── users/
    └── get-user.bru

각 환경 파일의 구조는 다음과 같다.

vars {
  base_url: http://localhost:3000
  client_id: dev-client
}
vars:secret [
  client_secret,
  access_token
]

vars:secret으로 선언한 변수는 .gitignore에 자동 추가되는 .env 파일에 저장되어 민감 정보가 저장소에 올라가지 않는다.

Bruno 스크립트로 토큰 자동화

Bruno도 요청 파일 안에 script:pre-request와 script:post-response 블록을 지원한다. 아래는 로그인 요청의 응답에서 토큰을 추출해 환경 변수로 저장하는 예시다.

script:post-response {
  const data = res.getBody();
  bru.setEnvVar('access_token', data.access_token);
  bru.setEnvVar('token_expiry', Date.now() + data.expires_in * 1000);
}

이후 다른 요청 파일에서 {{access_token}}을 Authorization 헤더에 참조하면 된다. Postman과 API는 다르지만 개념은 동일하다.

Bruno의 script:pre-request에서는 bru.getEnvVar()로 변수를 읽고, 조건에 따라 다른 값을 세팅하는 로직을 넣을 수 있다. 다만 Postman의 pm.sendRequest()처럼 Pre-request 단계에서 외부 HTTP 요청을 직접 보내는 기능은 버전에 따라 지원 범위가 다르므로, 사용 중인 Bruno 버전의 릴리스 노트를 확인하는 것이 좋다.

팀 협업을 위한 환경 변수 관리 전략

환경 변수를 잘 정의해도 관리 방식이 잘못되면 팀 협업에서 문제가 생긴다. 실무에서 쓸 수 있는 규칙 몇 가지를 정리하면 다음과 같다.

  • 민감 정보는 Current Value(Postman) 또는 secret 변수(Bruno)에만 저장한다. Initial Value나 일반 vars에 실제 시크릿을 넣으면 내보내기나 커밋 시 노출될 수 있다.
  • 환경 파일을 역할별로 나눈다. Development, Staging, Production 환경을 별도 파일로 관리하면 실수로 프로덕션 환경에서 테스트하는 사고를 줄일 수 있다.
  • 변수 이름 컨벤션을 팀 내에서 통일한다. baseUrl과 base_url이 혼재하면 스크립트 오류를 찾는 데 시간이 걸린다. snake_case 또는 camelCase 중 하나를 선택해 문서화해 두는 것이 좋다.
  • Postman 환경은 Export 후 Git에 포함시키되, Current Value는 제외한다. Bruno는 파일 기반이므로 .bru 환경 파일 자체를 커밋하고 .env는 .gitignore로 제외하면 된다.

컬렉션 Runner와 자동화 테스트 연동

환경 변수 자동화의 효과는 단순 수동 테스트를 넘어 CI/CD 파이프라인과 연결할 때 극대화된다.

Postman은 Newman이라는 CLI 러너를 공식 제공한다. 컬렉션 파일과 환경 파일을 내보낸 후 아래처럼 실행하면 GitHub Actions나 Jenkins 같은 파이프라인에서 API 테스트를 자동으로 돌릴 수 있다.

newman run collection.json \
  --environment staging.json \
  --reporters cli,junit \
  --reporter-junit-export results.xml

Bruno는 bru CLI를 제공한다. 컬렉션 폴더를 그대로 사용하므로 별도 Export 없이 바로 실행 가능하다.

bru run --env staging --output results.json

CI 환경에서는 시크릿 변수를 환경 파일에 직접 넣지 않고 파이프라인의 시크릿 관리 기능(GitHub Actions Secrets, GitLab CI Variables 등)에서 주입하는 방식이 안전하다. Newman의 경우 --env-var 옵션으로, Bruno CLI의 경우 운영체제 환경 변수를 .env 파일 대신 참조하도록 설정할 수 있다.

실무에서 자주 하는 실수와 해결 방법

변수가 적용되지 않는 경우

Postman에서 {{access_token}}이 그대로 전송되는 경우가 있다. 대부분 활성화된 환경이 없거나 변수 이름의 대소문자가 다를 때 발생한다. 요청을 보내기 전 우측 상단 환경 드롭다운이 올바른 환경을 가리키는지, 변수 이름이 정확히 일치하는지 먼저 확인한다.

Pre-request Script 실행 순서 혼란

컬렉션 레벨 스크립트와 폴더 레벨 스크립트, 요청 레벨 스크립트가 모두 있을 때 실행 순서를 잘못 이해하면 예상치 못한 변수 덮어쓰기가 발생한다. Postman의 실행 순서는 컬렉션 → 폴더 → 요청 순이다. 공통 토큰 갱신 로직은 컬렉션 레벨에, 특정 요청에만 필요한 변수 세팅은 요청 레벨에 두는 것이 명확하다.

토큰 만료 시각 계산 오류

expires_in 값이 밀리초가 아닌 초 단위로 오는 경우가 대부분이다. Date.now()는 밀리초를 반환하므로 expires_in * 1000을 더해야 한다. 이 부분을 놓치면 토큰이 갱신됐음에도 만료된 것으로 판단해 매 요청마다 불필요한 토큰 발급 요청이 발생한다.

Postman과 Bruno, 어떤 상황에 무엇을 쓸까

두 도구는 지향점이 다르기 때문에 팀 상황에 따라 선택이 달라진다.

기준PostmanBruno
팀 공유 방식클라우드 워크스페이스Git 저장소
가격무료 플랜 제한 있음완전 무료 오픈소스
CLI 러너Newmanbru CLI
파일 형식JSON.bru (텍스트)
오프라인 사용제한적완전 지원

대규모 팀에서 비개발 직군과 함께 API 문서를 공유하거나 Mock 서버가 필요하다면 Postman이 유리하다. 반면 개발팀 내부에서 Git 기반으로 컬렉션을 코드처럼 관리하고 싶다면 Bruno가 더 잘 맞는다. 두 도구 모두 환경 변수 자동화의 핵심 기능을 지원하므로, 어느 쪽을 쓰더라도 이 글에서 다룬 자동화 패턴을 그대로 적용할 수 있다.

반복적인 수작업을 줄이는 것은 단순한 편의 문제가 아니다. 토큰 갱신을 깜빡해 발생하는 디버깅 시간, 환경 변수 오기입으로 생기는 오류 추적 시간이 쌓이면 하루 업무의 상당 부분을 낭비하게 된다. 환경 변수와 스크립트 자동화를 제대로 셋업하는 데 드는 시간은 길어야 한두 시간이고, 그 효과는 프로젝트 기간 내내 지속된다.