[QA] Postman 테스트 스크립트 작성하기

jm.0116·2024년 12월 23일

API 자동화 테스트

목록 보기
2/4

📌 Postman 테스트 스크립트 작성하기

이번에는 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()문의 자동 오류 처리 기능이 있기 때문에 자동으로 테스트를 실패처리 및 그 이유를 명확히 알려줍니다. 또한, 코드의 가독성이 떨어지는 것은 덤이고요. 그러기 때문에 정말 필요한 상황이 아니라면 지양하는 것이 맞다는 저의 생각입니다. 제 생각이 잘못되었다고 생각하시면 댓글 남겨주세요!


✔ [GET] URL 상태 체크

{{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으로 반환되는지 확인한다.
});

사이트가 정상적으로 작동하는지에 대해 간단하게 체크를 해보았습니다.

✔ [GET] 모든 Tools 불러오기

{{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");

✔ [GET] 하나의 Tool 불러오기 / 데이터 스키마 테스트

{{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의 도움을 받았지만... 그래도 스키마 체크 정도는 필요할 것 같아서 간단하게라도 해보았다.

✔ [POST] 클라이언트 생성

{{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값에 넣어 주면 된다.

✔ [POST] 새 주문 생성

{{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);
});

✔ [POST] 새 주문 생성 (존재 X 제품)

{{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.");
});

✔ [POST] 새 주문 생성 (재고 없는 제품)

{{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.");
});

✔ [GET] 주문 불러오기

{{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 버튼을 누르면 됩니다.

✔ [PATCH] 주문 업데이트 하기

{{baseURL}}/orders/:orderId
{
 "customerName" : "Joe {{$randomLastName}}",
 "comment": "지금 테스트 중입니다. 체크 부탁드립니다."
}
pm.test("TC-009 / Status Code 204", function () {
    pm.response.to.have.status(204);
});

✔ [GET] 하나의 주문 불러오기

{{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);
    }

});

✔ [DELETE] 주문 삭제하기

{{baseURL}}/orders/:orderId
pm.test("TC-010 / Status Code 204", function () {
    pm.response.to.have.status(204);
});

✔ [GET] 삭제된 주문 호출하기 (실패 유도)

{{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")
});

✔ Collection 한 번에 실행해보기

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

짜잔, 완료!


🎉 마치며...

자세하게 작성하지는 않았지만 간단하게라도 API 테스트를 어떻게 해야할 지, 어떻게 구현해야 할 지 알아보는 시간을 가졌습니다. Javascript를 잘 할줄 알아야 하지만 요즘은 ChatGPT도 있기 때문에 어떤 식으로 내가 구현을 해야겠다라는 로직만 머리에 둔다면 어렵지 않게 할 수 있을 겁니다.

profile
QA Engineer

1개의 댓글

comment-user-thumbnail
2024년 12월 24일

진심으로 도움이 되네요 감사합니다~! :)

답글 달기