화면을 개발할 때 백엔드 api를 기다리며 개발을 홀딩하다가 api가 배포되면 그제야 화면에 연동하는 작업을 하게 되는 경우가 많다. 물론 이 과정도(실제 api와 연동) 필요한 과정이지만 기다리는 시간이 낭비된다. 이때 api spec만 알면 간편하게 목 서버를 만들어서 개발하다가 api가 배포되면 url만 교체해서 확인하면 시간을 절약할 수 있다.
목 서버를 만드는 방법은 위 링크처럼 여러 가지가 있지만 나는 collections에 샘플 req/res를 만들어놓고 mock server로 전환하는 편이다.
이때 아래와 같이 샘플 response를 미리 저장해야 한다. 각 api에서 add example을 통해 등록한다.
그리고 콜랙션을 목서버로 만든다. info를 누르면 목 서버를 만들 수 있는 창이 뜬다.
이때 url을 환경변수로 설정해두면목서버를 만들 때 해당 목 서버가 자동으로 환경변수로 등록되어 url 전환이 쉬워진다. 또한나중에 api가 다른 서버에 배포되었을 때 환경변수로 url을 등록만 해놓는다면 바로 전환해서 요청이 가능하므로 매우 유용하다.
환경변수는 왼쪽 environments 탭에서 설정 가능하다.
추가적으로 만든 목 서버/collection에 대한 api doc을 발행할 수도 있다.
documentation -> publish 하면 발행이 되고 최종 발행이 되면 url 생성된다. 이 url로 다른 사람도 나의 목 서버의 스펙을 확인, api를 요청할 수 있다(private 한 발행도 가능하다).
api 두 개를 순차적으로 요청할 때, 첫 번째 api 결과로 얻은 list안의 어떤 값을 두 번째 api의 요청 값에 넣어 순차적으로 테스트하는 방법을 알아본다. 이전 글에서 다룬 chaining test랑도 비슷하지만, chaining test에서는 object안의 한 항목을 variable로 set 해서 전달했다면, 여기서는 마치 for loop을 도는 것처럼 list안의 항목을 하나씩 돌아 테스트한다.
이전에 다룬 bulk test와도 비슷하지만 별도의 csv파일을 활용하지 않고 진행하는 것에 차이가 있다.
여기서 status = '01' 이면 active, '01'이 아니면 inactive이다. 원하는 것은 active 한 object의 playerId를 꺼내서 다음 api의 request항목(여기서는 path param)에 넣어 순차적으로 요청하는 것이라면, 테스트 코드를 어떻게 작성해야 할까.
const playerIds = pm.collectionVariables.get("playerIds");
pm.test("Status code is 200", function () {
pm.response.to.have.status(200); //6. 현재 요청이 성공인지 우선 확인
});
if(playerIds && playerIds.length > 0){ //collection-var의 array에 데이터가 있는지 확인하고, 있으면
postman.setNextRequest("get affiliate by asp"); //7. 자기자신을 다시 실행
}else{
postman.setNextRequest(null); //7. 없으면 끝
}
이렇게 두고 테스트하니 아래처럼 첫 번째 api는 1번 두 번째 api는 playerIds array의 크기(여기서는 29)만큼의 루프를 모두 돌아 정상 실행됨을 확인할 수 있었다.
request로 사용할 데이터가 든 파일을 준비한다. csv 확장자로 저장된 파일이어야 하며, 최상단에는 지칭하는 이름이 들어있어야 한다(노트패드나 엑셀에서 csv파일을 만들 수 있다).
포스트맨에서 collection -> runner 클릭하고 콜랙션의 api를 옆으로 드래그한다. 필요시 순서를 맞추고, 테스트할 api를 선택한다.
오른쪽 영역에서 위 csv파일을 데이터 부분에서 csv 파일을 불러온다.
preview를 눌렀을 때 아래와 같이 팝업이 뜨면 정상적으로 읽힌 것이다.
자 이제 파일을 준비했으니, 저 변수를 가져올 부분을 세팅해보자. 나는 저 변수를 POST 요청의 항목으로 사용할 예정이라 아래와 같이 수정해주었다.
가. pre-request script에서 파일에서 읽어 온 값을 변수 처리한다. 어떤 변수로 세팅해야 할지는 상황에 따라 다르겠다. 이전 글을 보면 변수의 범위에 대해 언급한 적이 있는데, 동일하게 생각해서 설정하면 된다.
var cardNo = pm.iterationData.get("card") //csv파일의 각 줄의 card부분을 가져와 변수 세팅
var zipcode = pm.iterationData.get("zipcode") //csv파일의 각 줄의 zipcode부분을 가져와 변수 세팅
console.log(cardNo) //로그
pm.collectionVariables.set("card", cardNo); //위 cardNo를 콜랙션 변수로 세팅
pm.collectionVariables.set("zipcode", zipcode); //위 zipcode를 콜랙션 변수로 세팅
나. body 부분을 수정한다. 변수가 들어갈 부분을 수정해준다.
다. 잘 들어갔는지 확인. 테스트 코드로 확인한다.
pm.test("request 변수 확인", function () {
var req = JSON.parse(pm.request.body.raw); //request body를 가져와서
console.log(req) //로그찍고
console.log(req[0].card) //string "9460777788890000"
console.log(pm.iterationData.get("card"))//number 9460777788890000
//parseInt(req[0].card)로 number로 바꿔서 비교해야 같게 나옴
pm.expect(parseInt(req[0].card)).to.eql(pm.iterationData.get("card"));
pm.expect(parseInt(req[0].address.zipcode)).to.eql(pm.iterationData.get("zipcode"));
});
라. 위 가~다 과정을 하고 나서 꼭 ctrl+s 를 눌러서 저장을 해주고, 다시 collection의 runner로 돌아와서 Run api-testing을 클릭한다.
테스트가 성공하는 것을 볼 수 있다. 만약 실패해도 뭐가 틀렸는지 알려주기 때문에 바로 수정하면 된다.
참고로 각 요청을 클릭하면 실제로 어떤 json이 요청 나가고 들어왔는지 볼 수 있다.
참고
1. csv파일의 특성 상 숫자 형의 맨 처음 오는 0은 잘리니까 조심해야 한다(사진에서도 파일에는 0이 있지만 포스트맨에서 불러왔을 때에는 0이 없어지는 것이 확인된다). 해결법이 있을 법도 한데,, 아직 없는 것 같다. csv파일을 json포맷으로 바꿔서 했다는 글만 있다.
2. 그리고 csv 안의 숫자의 길이가 16자리 이상이면 포스트맨이 값을 알아서 변환해버리는 이슈가 있다. 변수를 불러올 때 자바스크립트의 Number를 사용해서 생기는 이슈라고는 하는데 어쨌든 request와 다른 값으로 쏘는 것은 명백한 이슈기 때문에 숫자를 문자로 바꿔서 요청할 수 있게끔 지원해달라는 문의글이 최신으로도 올라오고 있다. 이를 방지하려면 아래와 같이 csv안의 숫자 앞뒤로 "(큰따옴표)를 넣어주면 되긴 하지만.. 데이터가 많을수록 귀찮아질 것이기에.. 아래의 json변환 방법을 사용하려 쏘는 게 더 나을 것 같다.
위 사이트에서 미리 준비된 csv를 선택하면 아래에 결과를 볼 수 있다. 여러 포맷으로 변환해주는데 포스트맨에서는 맨 처음 양식을 지원하기 때문에 csv to json으로 변환해주고 download를 눌러주면. json파일이 받아진다.
만들어진 파일을 열어본다(위 사진의 result data에서도 확인가능하다).
자동으로 타입을 판별해서 그런지 zipcode가 숫자 타입으로 json이 만들어졌는데, 이를 문자열로 바꿔서 다시 만들도록 한다(api request에서 문자로 보내야 하는지 숫자로 보내야 하는지에 따라 다르게 설정하면 된다).
사이트 output 옵션 중에 강제로 stringify하는 곳이 있는데, 비워두면 전체를 문자열화, 위치를 콤마로 구분해서 넣어주면 그 곳만 문자열화 해준다. 우리는 두번째에 위치한 zipcode를 문자열화 해야 하니 2를 넣어주고 다시 csv to json을 눌러준다. 아래에 문자열로 바뀐 json을 확인한다.
포스트맨에서 json파일을 불러오고 preview버튼을 누르면 아까 csv에서는 사라졌던 0이 잘 들어와 있는 것을 볼 수 있다.
csv로 테스트했을 때는 다 숫자로 읽어와서 테스트 코드도 숫자로 변환하는 부분이 있었는데, json에서는 이를 유동적으로 바꿀 수 있어서 더 좋은 것 같다. 우리는 지금 모든 값을 문자화 했으니 테스트 코드도 문자 비교로 바꿔야 통과한다.
pm.test("request 변수 확인", function () {
var req = JSON.parse(pm.request.body.raw);
console.log(req)
pm.expect(req[0].card).to.eql(pm.iterationData.get("card"));
pm.expect(req[0].address.zipcode).to.eql(pm.iterationData.get("zipcode"));
});
마치며..
csv는 숫자 값이면 (숫자가 아니어도 숫자 꼴이기만 하면; ex. 카드번호, 폰번호) 숫자로 인식해서 예상하지 못한 문제가 생길 수 있는데, json으로 변환하면 이를 조절할 수 있으니 json으로 테스트하는 게 더 정확하고 예측 가능한 것 같다!
목표: collection, pre-request script, tests 를 활용하여 chaining test를 진행해본다.
콜렉션에 GET/POST api를 저장해놓은 후 GET api로 정보를 불러와서 불러온 값을 POST api 실어 보내본다.
0. 환경변수 세팅(필요 시)
테스트로 name = purin 값을 넣어놨다.
1. 콜랙션에 api 세팅
2. GET api의 test script 작성
pm.test("정상 요청일 때 변수 저장", function () {
if(pm.response.to.have.status(200)){ //정상 처리 되었을 경우
var jsonData = pm.response.json(); //결과를 json으로 만들고
var username = jsonData[0].username; //결과json의 첫번째 덩어리의 username을 변수화
var phone = jsonData[1].phone; //결과json의 두번째 덩어리의 phone을 변수화
console.log("check username: " + username) //혹시 몰라 로깅
pm.collectionVariables.set("username", username); //콜랙션 변수로 지정(이름, 값)
pm.collectionVariables.set("phone", phone); //콜랙션 변수로 지정(이름, 값)
}else{
console.log("this got error?") //정상 처리 되지 않았을 경우 로그 남김
}
});
username과 phone이란 값을 결과 값에서 가져와 저장하는 것을 알 수 있다.
실행시켰을 때 정상적으로 되는 것 확인.
참고로 console.log는 어디에 남냐면 포스트맨의 메뉴표시줄에 view > show postman console에서 확인 가능하다.
클릭하면 새로운 창이 뜨며 로그가 쌓이는 것을 볼 수 있다.
3. POST api의 스크립트 작성
우선 body 부분에 저장하고하는 json을 작성한다. 이 때 변수는 {{중괄호}} 처리한다.
pm.test("request 변수 확인", function () {
var req = JSON.parse(pm.request.body.raw); //request body(보내는 요청) 값을 json으로 변환
console.log(req) //로깅
pm.expect(req[0].username).to.eql("Bret"); //보내는 요청의 첫번째 덩어리의 username이 Bret이랑 완전히 같은지 확인
});
pm.test("Successful POST request", function () { //상태 코드 확인
pm.expect(pm.response.code).to.be.oneOf([201, 202]);
});
pm.test("Status code name has string", function () { //상태 코드 문자열 확인
pm.response.to.have.status("Created");
});
위와 같이 작성하고 send를 누르면 name = purin(환경 변수) / username = Bret(콜렉션 변수) / phone (콜렉션 변수) 가 자동으로 들어가며 테스트가 성공한다. 왜 일까?
중괄호된 변수는 포스트맨이 알아서 변수를 찾아서 넣어주기 때문에 따로 관여할 필요가 없다.
하지만 만약 변수에 약간의 수정을 가미해야 한다면?
pre-request script에서 진행하면 된다(오른쪽에 snippet을 활용하여 코드를 작성하면 더 쉽다).
Json탭을 선택한 후 왼쪽 칸에 1번에서 복사해 둔 json을 붙여 넣기 하고 json to schema버튼을 누른다(min/full 아무거나 무관).
해당 사이트는 json을 분석하여 기본적인 json의 구조를 분석해준다. 타입이 무엇인지(array, object 등), 각 항목이 필수 값인지(우선 json의 모든 값이 필수라고 지정되지만 손으로 수정하면 된다) 어떤 타입인지(string, number 등)를 기본적으로 알려주며 maxItem, maxLength, pattern 등 다양하게 지정 가능하지만 위 사이트에서는 거기까지는 해주지 않고 필요할 경우 직접 수정하면 된다.
pm.test('Schema is valid', function() {
var data = pm.response.json(); //결과 값을 json으로 변환하여 data에 담고
pm.expect(ajv.validate(schema, data)).to.be.true; //검증 값이 true(참)인지 확인
//ajv.validate(schema, data) : ajv라이브러리의 validate함수를 이용하여 schema가 data랑 맞는지 검증
});
test results 섹션에 테스트 이름과 테스트 통과 여부가 잘 나오는 것을 알 수 있다.
형태가 바뀌어서는 안되는 api를 검증할 경우(특히 외부에 공개해야 하는 api 일 경우 api doc과 일치하는지 확인할 때) 유용하게 쓰일 테스트이다.
이번 테스트에서는 free fake api 제공하는 jsonplaceholder의 샘플 api를 사용한다.
//GET or POST
https://jsonplaceholder.typicode.com/users
1. 환경변수 생성
url이 반복되니 url을 환경변수로 저장한다.
url을 환경변수로 생성하면 서버별로 콜랙션을 따로 만들 필요 없이 환경변수의 값만 바꿔주면 된다(ex. 개발서버/qa서버별로 콜랙션을 나눌 필요가 없고 환경변수에 값만 변경하여 돌릴 수 있다).
오른쪽 상단에 있는 눈 마크에서 설정할 수 있다. environment 와 global이 있는데 environment는 환경에 따라 전환하여 쓰는 값이고 global은 환경에 상관없이 공통으로 쓸 값이다. url은 environment와 성격이 더 맞기 때문에 environment의 add를 눌러 저장한다.
아래와 같이 환경에 맞게 url/기타 변수 등을 입력하고 환경변수의 이름을 지정한 후 save를 누른다.
그리고 다시 api를 쏘는 공간으로 돌아와서 주소 값을 방금 설정한 변수로 세팅해준다. 중괄호 두 개를 사용하면 변수를 불러올 수 있다.
여기서 처음에 잘 안될 수 있는데, 이는 환경 지정하지 않았기 때문이다. 오른쪽 상단에서 올바른 환경변수(real-server)를 선택해주자.
2. snippets 스크립스 설명
snippet을 활용한 기본 테스트를 해본다.
처음 보이는 부분은 변수 가져오기/저장하기/비우기에 관한 부분이다. 직접적인 테스팅은 아니고 테스트 스크립트에서 필요할 때 불러다가 사용하면 된다.
맨 위의 sene a request와 response body: convert xml body to a json을 제외한 나머지는 모두 테스팅 코드이다. 눌러보면 아래와 같은 형태를 하고 있음을 알 수 있다.
pm.test("테스트 이름/설명", function () {
//어떻게 테스트 할지 로직
pm.expect(); //테스트 기대값 확인하는 함수
});
pm이라는 라이브러리에서 test라는 함수를 사용하고 있다. 첫 번째 변수는 테스트 이름이고 두 번째 매개변수인 함수가 실제 로직이 들어갈 곳이다. 보통 expect 함수를 써서 결과 값을 확인하게 되어 있다.
snippet에서 볼 수 있는 함수들은 아래와 같다.
pm.test("Status code is 200", function () {
pm.response.to.have.status(200); //status 가 200을 가지고 있는지
});
pm.test("Body matches string", function () {
pm.expect(pm.response.text()).to.include("Bret"); //결과 어딘가에 Bret 이라는 단어를 포함하고(include) 있는지
//pm.response.text() : 결과를 string화 함
});
pm.test("Your test name", function () {
var jsonData = pm.response.json(); //결과 값을 json으로 만들고
pm.expect(jsonData[0].id).to.eql(1); //array의 첫 번째 덩어리의 id 값이 1인지 확인
//jsonData[0].id : 코드에서 대부분의 것은 0부터 시작이라 0이 첫 번째이고 결과 값이 object가 아닌 array여서 index([n])를 넣어줘야함
});
pm.test("Body is correct", function () {
pm.response.to.have.body('[{"id":1}]'); //결과가 이것과 완전히 동일한지 확인
});
pm.test("Content-Type is present", function () {
pm.response.to.have.header("Content-Type"); //특정 헤더가 있는지 확인
});
pm.test("Response time is less than 200ms", function () {
pm.expect(pm.response.responseTime).to.be.below(200); //응답시간이 200ms 이하인지 확인
});
pm.test("Successful POST request", function () {
pm.expect(pm.response.code).to.be.oneOf([201, 200]); //결과 http status code가 둘 중 하나인지 확인
});
pm.test("Status code name has string", function () {
pm.response.to.have.status("OK"); //결과 http status code가 숫자가 아니라 문자로 올 때(대소문자 구분함에 주의)
});
/////
var schema = {
"items": {
"type": "boolean"
}
};
var data1 = [true, false];
var data2 = [true, 123];
pm.test('Schema is valid', function () {
pm.expect(tv4.validate(data1, schema)).to.be.true; //data1의 틀이 schema와 맞는지 확인
pm.expect(tv4.validate(data2, schema)).to.be.false; //data2의 틀이 schema와 맞는지 확인
});
기본 snippet을 통하여 값 결과 값 검사, 상태 확인, 결과 format 확인(schema) 등이 가능하다.
앞으로 자주 쓸 문법은 아무래도 결과 값을 json화 하여 변수를 다루는 부분일 것이다. 또한 eql과 have/include가 의미적으로 다르기에 헷갈리면 안된다.
앞.to.have.뒤 //앞 항목이 뒤를 가지고 있는지(명확)
앞.to.include.뒤 //앞 항목이 뒤를 포함하는지(존재성)
앞.to.not.have.뒤 //부정할 때 not의 위치 중요(to 다음; include 등에서도 활용가능)
앞.to.eql(뒤) //앞이 뒤랑 값이 같은지 확인(데이터 값 확인)
pm.response... // 여기 안에 결과가 들어있고
var jsonData = pm.response.json(); //결과 값을 json으로 만드는 부분; json화 해야 데이터를 가져오기가 쉽다.
포스트맨이란 API 개발을 보다 빠르고 쉽게 구현 할 수 있도록 도와주며, 개발된 API를 테스트하여 문서화 또는 공유 할 수 있도록 도와주는 플랫폼이다. 포스트맨으로는 api 요청을 하고 관련 스크립트를 저장해서 export/import 할 수 있을 뿐만 아니라, 다양한 환경/변수 등에서 테스트를 하고 그 결과를 분석하고, 소스코드와 연동하여 ci를 가능하게 한다.
포스트맨의 다양한 기능이 있지만 당분간 테스트 작성법에 대해 초점을 두고 알아보려고 한다.
앞으로 작성할 글을 읽기 전 전제사항은 다음과 같다.
포스트맨으로 api 요청을 해 본 적이 있다.
포스트맨의 다양한 기능을 사용해 본 적이 있다.
포스트맨의 용어들과 친숙하다.
포스트맨과 친숙하지 않은 사람들을 위해 간략히 아래 참고 링크를 공유한다.
특히 포스트맨의 collection에 대해 알아둬야 할 필요가 있다.
포스트맨은 api를 관리하기 위한 묶음으로 collection을 제공하는데 이 묶음 별로 변수를 설정하고 테스트를 관리할 수 있다(또한 보기도 좋으니 일석이조 아닌가).