이번에는 Postman으로 API 테스트를 자동화하기 위해 스크립트를 작성해보도록 하겠습니다.

먼저 위와 같이 간단한 테스트만 구현해보았으며 https://github.com/vdespa/quick-introduction-to-postman/blob/main/simple-tool-rental-api.md#Status를 참고 하여 제작하였습니다.
API 문서를 읽어보고 화면에 띄어두고 작성하면 편합니다.
try...catch문을 사용을 안하셨는데 왜 그러셨나요?
저도 처음에 스크립트 작성 할 때 try...catch을 남발 했었는데 결론부터 말하자면 pm.expect()문의 자동 오류 처리 기능이 있기 때문에 자동으로 테스트를 실패처리 및 그 이유를 명확히 알려줍니다. 또한, 코드의 가독성이 떨어지는 것은 덤이고요. 그러기 때문에 정말 필요한 상황이 아니라면 지양하는 것이 맞다는 저의 생각입니다. 제 생각이 잘못되었다고 생각하시면 댓글 남겨주세요!

{{baseURL}}/status
먼저 API 주소를 위와 같이 Collection Variables에 저장을 해주었습니다.
Variables에 저장을 해두어야 variables만 수정해도 모든 시트에 동일하게 수정됩니다.
pm.test("TC-001 / Status Code 200", () => {
pm.response.to.have.status(200);
const response = pm.response.json(); // json으로 반환되는 값을 javascript가 활용할 수 있게 바꿔준다.
console.log(response["status"]);
pm.expect(response["status"]).to.eql("UP"); // UP으로 반환되는지 확인한다.
});
사이트가 정상적으로 작동하는지에 대해 간단하게 체크를 해보았습니다.
{{baseURL}}/tools
pm.test("TC-002 / Status Code 200", function () {
pm.response.to.have.status(200);
});
pm.test("TC-002 / Tools 정상 확인", function () {
const response = pm.response.json();
pm.expect(response).to.be.an('array');
pm.expect(response[0], "첫 번째 요소가 존재하지 않습니다.").to.not.be.undefined; // 첫 번째 요소가 존재하는지 확인
const tools = response.filter((tool) => tool.inStock === true); // 재고가 있는 항목만 필터링
const noStock = response.filter((tool) => tool.inStock === false); // 재고가 없는 항목만 필터링
let randomNumber = Math.floor(Math.random() * Object.keys(tools).length);
let nostockrandomNumber = Math.floor(Math.random() * Object.keys(noStock).length);
pm.collectionVariables.set("randomToolsId", tools[randomNumber]["id"])
pm.collectionVariables.set("noStockrandomToolsId", noStock[nostockrandomNumber]["id"])
});

먼저 response body 값을 확인하면 위와 같이 값이 반환 되는 것을 확인할 수 있다.
pm.collectionVariables.set("", )를 활용하여 동적으로 값을 variable에 넣는 것을 확인 할 수 있다.
// Local Variable 설정
pm.variables.set("myVariable", "value");
// Collection Variable 설정
pm.collectionVariables.set("myCollectionVariable", "value");
// Environment Variable 설정
pm.environment.set("myEnvVariable", "value");
// Global Variable 설정
pm.globals.set("myGlobalVariable", "value");
{{baseURL}}/tools/:toolId
randomToolId를 이미 CollectionVariables에 설정 해 두었기 때문에 이를 활용하여 아래와 같이 Parameters를 설정한다.

{{randomToolsId}}와 같이 variables를 사용할 때는 {{ }}를 활용하여 동적으로 사용할 수 있다.
pm.test("TC-003 / Status Code 200", function () {
pm.response.to.have.status(200);
});
pm.test("TC-003 / 데이터 스키마 체크", () => {
const Ajv = require("ajv");
const ajv = new Ajv(); // Ajv 인스턴스 생성
const response = pm.response.json(); // 응답 데이터를 JSON 형식으로 파싱
// JSON 스키마 정의
const schema = {
"type": "object",
"properties": {
"id": { "type": "integer" },
"category": { "type": "string" },
"name": { "type": "string" },
"manufacturer": { "type": "string" },
"price": { "type": "number" },
"current-stock": { "type": "integer" },
"inStock": { "type": "boolean" }
},
"required": ["id", "category", "name", "manufacturer", "price", "current-stock", "inStock"],
"additionalProperties": false
};
// 데이터 검증
const validate = ajv.compile(schema);
const valid = validate(response); // response가 스키마에 맞는지 검증
// 검증 결과에 따라 Pass/Fail 처리
if (valid) {
pm.expect(valid).to.be.true; // 검증이 성공하면 Pass
console.log("JSON 데이터가 스키마에 맞습니다.");
} else {
pm.expect(valid).to.be.true; // 검증이 실패하면 Fail
console.log("JSON 데이터가 스키마에 맞지 않습니다.");
console.log(validate.errors); // 에러 메시지 출력
}
});

JSON 스키마가 맞는지 체크하는 동작까지 구현해 보았다. ChatGPT의 도움을 받았지만... 그래도 스키마 체크 정도는 필요할 것 같아서 간단하게라도 해보았다.
{{baseURL}}/api-clients
추후에 새 주문을 생성하기 위해선 클라이언트를 생성하여 accessToken을 발급받아야 한다.
POST를 통해서 Body 값을 넘겨주면 이를 응답 받고 201 Created가 서버에서 돌아오면 된다.
{
"clientName": "{{$randomFullName}}",
"clientEmail": "{{$randomFirstName}}@gmail.com"
}
근데 여기서 clientName과 clientEmail을 매번 똑같이 하면 테스트의 정확성이 떨어질 수 있지 않겠는가? 그래서 Postman에는 또 랜덤으로 이름을 넘겨줄 수 있게 만들었다. 위와 같이 작성하면 된다.
pm.test("TC-004 / Status Code 201", () => {
pm.response.to.have.status(201);
});
pm.test("TC-004 / accessToken 여부 확인", () => {
const response = pm.response.json();
// accessToken 속성이 존재하는지 확인
pm.expect(response).to.have.property("accessToken");
// accessToken이 문자열 타입인지 확인
pm.expect(response.accessToken).to.be.a("string");
// accessToken을 collection 변수로 설정
pm.collectionVariables.set("apiToken", response.accessToken);
});
여기서 또 중요한 부분이 있는데 accessToken이 생성되면 이를 저장해두어야 뒤의 테스트에서 계속 Token을 활용할 수 있다.
근데 토큰을 어떻게 사용해야 하지?
앞으로 계속 설정을 해두겠지만 위와 같이 Authorization 항목 -> Bearer Token 선택 후 저장해둔 apiToken을 Token값에 넣어 주면 된다.
{{baseURL}}/orders
{
"toolId": {{randomToolsId}},
"customerName": "{{$randomFullName}}"
}
Body에 위와 같이 설정한다.
pm.test("TC-005 / Status code is 201", function () {
pm.response.to.have.status(201);
});
pm.test("TC-005 / orderId 포함 여부 및 String 확인", () => {
const response = pm.response.json(); // 응답을 JSON 형식으로 파싱
// orderId 속성이 존재하는지 확인
pm.expect(response).to.have.property("orderId");
// orderId가 string 타입인지 확인
pm.expect(response.orderId).to.be.a('string');
// orderId를 collection 변수로 설정
pm.collectionVariables.set("orderId", response.orderId);
// 랜덤 번호 생성 후 collection 변수로 설정
let randomNumber = Math.floor(Math.random() * 9) + 1;
pm.collectionVariables.set("noExisttoolId", randomNumber);
});
{{baseURL}}/orders
{
"toolId": {{noExisttoolId}},
"customerName": "{{$randomFullName}}"
}
존재하지 않는 제품의 toolId를 전송하여 400 Bad Request가 넘어오는지 확인해본다.
pm.test("TC-006 / Status code is 400", function () {
pm.response.to.have.status(400);
});
pm.test("TC-006 / Error Message 여부 확인", () => {
const response = pm.response.json(); // 응답을 JSON 형식으로 파싱
// error 메시지가 포함되어 있는지 확인
pm.expect(response.error).to.include("Invalid or missing toolId.");
});
{{baseURL}}/orders
{
"toolId": {{noStockrandomToolsId}},
"customerName": "{{$randomFullName}}"
}
pm.test("TC-007 / Status Code 400", function () {
pm.response.to.have.status(400);
});
pm.test("TC-007 / No Stock Error Message 여부 확인", () => {
const response = pm.response.json(); // 응답을 JSON 형식으로 파싱
// error 메시지가 포함되어 있는지 확인
pm.expect(response.error).to.include("This tool is not in stock and cannot be ordered.");
});
{{baseURL}}/orders
pm.test("TC-008 / Status Code 200", function () {
pm.response.to.have.status(200);
});
pm.test("TC-008 / 주문 목록 확인", () => {
const response = pm.response.json(); // 응답을 JSON 형식으로 파싱
// 응답이 존재하는지 확인
pm.expect(response).to.not.be.undefined;
// 랜덤 번호를 생성하여 주문 ID를 설정
let randomNumber = Math.floor(Math.random() * Object.keys(response).length);
pm.collectionVariables.set("randomOrderId", response[randomNumber]["id"]);
console.log(response[0]);
});
만약 여러분이 주문 목록을 여러 개 불러오고 싶다면 [POST] 새 주문 생성에서 여러 번 Send 버튼을 누르면 됩니다.
{{baseURL}}/orders/:orderId
{
"customerName" : "Joe {{$randomLastName}}",
"comment": "지금 테스트 중입니다. 체크 부탁드립니다."
}
pm.test("TC-009 / Status Code 204", function () {
pm.response.to.have.status(204);
});
{{baseURL}}/orders/:orderId

pm.test("TC-010 / Status Code 200", function () {
pm.response.to.have.status(200);
});
pm.test("TC-010 / 주문 목록 확인 및 업데이트 확인", () => {
const response = pm.response.json();
if(response) {
pm.expect(response).to.not.be.undefined;
pm.expect(response.comment).to.include("지금 테스트 중입니다.")
console.log(response);
}
});
{{baseURL}}/orders/:orderId
pm.test("TC-010 / Status Code 204", function () {
pm.response.to.have.status(204);
});
{{baseURL}}/orders/:orderId
pm.test("TC-012 / Status Code 404", function () {
pm.response.to.have.status(404);
});
pm.test("TC-012 / 정상 삭제 확인", () => {
const response = pm.response.json();
pm.expect(response.error).to.include("No order with id")
});

매번 하나씩 누르면서 실행해도 되지만 모든 script가 작성 완료 되었다면 위와 같이 Run Collection을 클릭하여 한번에 실행 과정을 지켜봐도 됩니다.


짜잔, 완료!
자세하게 작성하지는 않았지만 간단하게라도 API 테스트를 어떻게 해야할 지, 어떻게 구현해야 할 지 알아보는 시간을 가졌습니다. Javascript를 잘 할줄 알아야 하지만 요즘은 ChatGPT도 있기 때문에 어떤 식으로 내가 구현을 해야겠다라는 로직만 머리에 둔다면 어렵지 않게 할 수 있을 겁니다.
진심으로 도움이 되네요 감사합니다~! :)