개발을 하다 페이지네이션 관련 테스트를 진행해야 하는 상황이 생겼다.
관계형 데이터를 하나하나 매핑해서 적재하는 작업이 번거로워,
보다 간편한 방법을 찾던 중 이 방식을 활용해봤는데, 매우 유용해서 포스팅하게 되었다.
이번 포스팅에서는 Postman 환경변수와 Script를 활용해 랜덤 데이터부터 관계형 데이터(FK)까지 한 번에 생성해보고,
이후에 Collection Runner로 대량 데이터를 만들어 보는 과정을 정리해보려 한다.
특히 TypeORM 관계 설정(@ManyToOne, @ManyToMany 등)을 해둔 DB에 손쉽게 데이터를 넣을 수 있는 방법이라,
대규모 테스트에도 편리하게 활용할 수 있다.
일일히 넣기 귀찮은 Token 자동화부터, 랜덤한 데이터 생성, Runner로 대규모 데이터 만들기 까지
지금부터 하나씩 알아보자.
환경변수(Environments) 설정
Postman에서 새 Environment를 하나 생성하자.
환경변수를 사용해 API URL이나 동적인 데이터를 간단히 관리할 수 있다.
이제 다음과 같이 host를 추가해주자.
host: ex) http://localhost:3000
이렇게 만들어두면, API 호출 시 {{host}}가 자동으로 http://localhost:3000으로 대체된다.
- Path 사용법:
{{host}}/movie
이제 이 Environment에 다양한 변수들을 추가시킬 것이다.
로그인 및 Token 자동화
예시로 POST {{host}}/auth/login을 호출했다고 가정했다.
이 API가 accessToken, refreshToken을 JSON으로 리턴한다고 할 때,
Script에서 아래처럼 코드를 작성해봤다.
좌측에 Pre-request랑 Post-reponse가 있는데,
해당 작업은 return값을 활용해야 하므로 Post-reponse 를 선택하고 스크립트를 작성하자.
pm.test("Status code is 201", function (){
pm.response.to.have.status(201)
const body = pm.response.json()
pm.environment.set("accessToken", body.accessToken);
pm.environment.set("refreshToken", body.refreshToken);
})
이 코드는 로그인 성공 시 응답으로 받은 accessToken과 refreshToken을 Postman 환경변수에 저장한다.
실행시키고 Environment에 가보면 Token이 정상적으로 추가되었을것이다.
이제 Environment에 있는 Token을 사용해서 Authorization 재사용 설정을 해보자.
1. 다른 API에서 Authorization 타입을 Inherit auth from parent로 설정한다.
2. 프로젝트 상단의 폴더에서 Authorization 타입을 Bearer Token으로 변경한 뒤,
Token 값에 {{accessToken}}을 입력한다.
이후 한 번만 로그인하면, 모든 요청에서 환경변수에 저장된 토큰 값을 사용하여 편리하게 인증할 수 있다.
이제 귀찮게 매번 헤더에 토큰을 추가해서 디버깅하지 않아도 된다!
랜덤 데이터 생성
Postman에서는 일부 빌트인 랜덤 변수를 제공한다. 예를 들어,
{
"name": "{{$randomFullName}}"
}
이렇게 작성하면, Body 데이터 생성할 때마다 새로운 이름으로 데이터를 생성할 수 있었다.
이 외에도 {{$randomCountry}}, {{$randomLoremSentence}},
{{$randomNoun}}, {{$randomAdjective}} 등 다양한 랜덤 변수가 있으니 참고하면 편리하다.
관계형 데이터 Seeding 설정
여기서는 TypeORM 예시를 들어서, Director와 Movie, 그리고 Genre 간의 관계를 다뤄봤다.
// Movie Entity
@ManyToMany(() => Genre, (genre) => genre.movies)
@JoinTable()
genres: Genre[];
@ManyToOne(() => Director, (director) => director.id, {
cascade: true,
nullable: false,
})
director: Director;
영화(Movie)에 장르(Genre)가 여러 개 매핑될 수 있으므로 @ManyToMany
감독(Director)은 @ManyToOne으로 지정해두었다.
FK인 Director와 Genre 먼저 생성해보자.
Director POST API
Director를 생성하는 API를 예시로 보겠다.
{
"name": "{{$randomFullName}}",
"dob": "1963-05-02T00:00:00.000Z",
"nationality": "{{$randomCountry}}"
}
이렇게 Body에 랜덤 변수들을 넣어서, 다양한 감독 정보가 쌓이도록 했다.
응답에서 받은 director의 id를 환경변수에 계속 누적하기 위해, Script에서 아래처럼 작성한다.
pm.test("Status code is 201", function () {
pm.response.to.have.status(201);
const body = pm.response.json();
let directorIds = pm.environment.get("directorIds");
if(!directorIds){
directorIds = body.id;
} else {
directorIds = directorIds + ',' + body.id;
}
pm.environment.set("directorIds", directorIds);
});
아까와 마찬가지로 return값을 활용해야 하므로 Post-reponse 를 선택하고 스크립트를 작성하자.
이 스크립트는 Director를 하나 만들 때마다 directorIds 문자열에 ,로 ID를 이어붙여서 저장했다.
Genre POST API
Genre도 마찬가지로, 아래처럼 Body를 작성하고 응답의 id를 모아서 genreIds에 저장했다.
{
"name": "{{$randomNoun}}"
}
pm.test("Status code is 201", function () {
pm.response.to.have.status(201);
const body = pm.response.json();
let genres = pm.environment.get("genreIds");
if(!genres){
genres = body.id;
} else {
genres = genres + ',' + body.id;
}
pm.environment.set("genreIds", genres);
});
아까와 마찬가지로 return값을 활용해야 하므로 Post-reponse 를 선택하고 스크립트를 작성하자.
이렇게 하면, Director IDs와 Genre IDs가 각각 환경변수에 누적되므로, Movie 데이터를 만들 때 이를 참조하면 된다.
Movie (PK) POST API
{
"title": "{{$randomNoun}} {{$randomAdjective}} {{$randomAlphaNumeric}}",
"detail": "{{$randomLoremSentence}}",
"directorId": {{director}},
"genreIds": [{{genres}}]
}
{{$randomNoun}}, {{$randomAdjective}}, {{$randomAlphaNumeric}} 등을 조합해 영화 제목을 랜덤하게 만들었다.
directorId와 genreIds에 아까 쌓은 Postman 환경변수를 사용하도록 설정했다.
const _ = require('lodash');
const directorIds = pm.environment.get('directorIds').split(",");
const randomDirectorId = _.sample(directorIds);
pm.environment.set("director", randomDirectorId);
const genreIds = pm.environment.get('genreIds').split(",");
const pickedGenreIds = [];
let failCount = 0;
while(pickedGenreIds.length < 3 && failCount < 20) {
const randomGenreId = _.sample(genreIds);
if(pickedGenreIds.includes(randomGenreId)) {
failCount++;
continue;
}
pickedGenreIds.push(randomGenreId);
}
pm.environment.set("genres", pickedGenreIds);
방금 Body에서 {{director}}, {{genres}}라는 변수를 썼다.
이 값들은 request 전에 필요하므로 Pre-request Script에서 작성하고, 무작위로 뽑아내준다.
Lodash의 .sample() 함수를 사용해서 directorIds 중 하나를 무작위로 뽑았다.
genreIds 중 3개까지만 골라서 genres 변수에 할당했다. (중복 방지를 위해 failCount도 추가)
{
"id": 917,
"title": "program cross-platform t",
"detail": {
"id": 917,
"detail": "Rerum voluptas omnis."
},
"director": {
"id": 229,
"name": "Kathy Cummings",
"dob": "1963-05-02T00:00:00.000Z",
"nationality": "Poland"
},
"genres": [
{
"id": 14,
"name": "driver"
},
{
"id": 21,
"name": "capacitor"
},
{
"id": 24,
"name": "sensor"
}
]
}
이렇게 FK 테이블(Director, Genre)을 먼저 여러 번 생성해두고,
Movie 생성 시점에 랜덤 FK를 골라 넣어주면, DB에 다양한 조합의 데이터가 쌓이게 된다.
Collection Runner로 대규모 데이터 만들기
마지막으로, Postman의 Collection Runner 기능을 사용하면 수백~수천 번 반복 호출도 간단하게 할 수 있다.
Runner 설정 방법
1. Postman에서 Collection 선택
2. Runner 실행 후, Iterations 값을 원하는 만큼 설정 (예: 10번, 50번, 100번 등)
3. Start Run 클릭하여 대량 데이터 생성.
이제 Director와 Genre API가 반복적으로 호출되어 환경변수에 ID를 계속 쌓아두고,
Movie API 호출 시 FK를 랜덤으로 할당해, DB에 방대한 테스트 데이터를 자동으로 넣을 수 있었다.
이렇게 생성된 영화 데이터들을 토대로 페이지네이션 기능을 테스트할 수도 있고,
다양한 시나리오별로 데이터를 쉽게 구성할 수 있어서 아주 편리했다 !
정리하자면,
1. Environment에 host부터 미리 셋팅을 해둔다.
2. 로그인 API로 accessToken을 받아 환경변수에 저장해두고, Bearer Token 설정을 Inherit해서 편리하게 인증한다.
3. 랜덤 변수({{$randomFullName}}, {{$randomNoun}}, {{$randomCountry}} 등)를 이용해 다양하게 테스트 데이터를 만든다
4. FK가 필요한 경우, Post-response Script에서 응답의 id를 환경변수에 저장하고,
PK 쪽(예: Movie) API에서 Pre-request Script로 무작위 샘플을 뽑아 Body에 넣어준다.
5. Collection Runner를 통해 대규모 반복 호출을 수행하면서 DB에 한꺼번에 많은 데이터를 쌓는다.
끝 !