Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for API Integration Testing Made Easy
Anudeep
Anudeep

Posted on

     

API Integration Testing Made Easy

Writing integration tests for API's is challenging in a micro-services world as it involves multiple API's from multiple components.

In this article we will be focusing on the two major challenges of writing API Integration Testing. It also talks about how to overcome them by using modern testing tools and techniques. We will be usingPactumJS to write automated API integration test cases.

GitHub logo pactumjs / pactum

REST API Testing Tool for all levels in a Test Pyramid

logo

PactumJS

BuildCoverageDownloadsSizePlatform

StarsTwitter

REST API Testing Tool for all levels in a Test Pyramid


PactumJS Demo









PactumJS is a REST API Testing Tool used to automate e2e, integration, contract & component (or service level) tests.

  • ⚡ Swift
  • 🎈 Lightweight
  • 🚀 Simple & Powerful
  • 🛠️ Compelling Mock Server
  • 💎 Elegant Data Management
  • 🔧 Extendable & Customizable
  • 📚 Clear & Comprehensive Testing Style
  • 🔗 Component, Contract & E2E testing of APIs

----------

Documentation

This readme offers an basic introduction to the library. Head over to the full documentation athttps://pactumjs.github.io

Need Help

We use GithubDiscussions to receive feedback, discuss ideas & answer questions.

Installation

# install pactum as a dev dependencynpm install --save-dev pactum# install a test runner to run pactum tests# mocha / jest / cucumbernpm install --save-dev mocha
Enter fullscreen modeExit fullscreen mode

or you can simply use

npx pactum-init
Enter fullscreen modeExit fullscreen mode

----------

Usage

Challenges

These are the two things of many that I personally felt challenging while writing API Integration Tests.

  1. Passing data across tests.
  2. Retry on failed expectations.

Example

It's always better to have an example to understand the core concepts of a topic under discussion.

Let's take a simple example of an e-commerce application with the following API endpoints for processing an order.

  • POST/api/orders (for placing an order)
  • POST/api/payments (for making a payment)
  • GET/api/payments/{payment_id} (for fetching the status of payment)

Workflow

To make things clear, the requests and responses shown below are overly simplified.

Step 1 - Place Order

A user comes in and makes aPOST request to/api/orders with the following payload to place an order.

Request Payload
{"product":"PlayStation 5"}
Enter fullscreen modeExit fullscreen mode

At the time of writing this article, it's highly impossible to buy the above product. At-least in some places. 🙂

Now the server responds with the following response body which contains the orderid.

Response
{"id":"1f4c99e9-12df-45d4-b455-98418f4e3b1e"}
Enter fullscreen modeExit fullscreen mode

This orderid is dynamically generated by the API server. We need to grab it and pass it to the other endpoints likepayments to complete the order.

Using any testing library, we can save the response in a variable and use them later. It works but not efficient. Because when we write integration tests for large scale applications, it forces us to pass significant amount of data between tests and API calls. Declaring intermediary variables will damage the readability of the code.

To overcome this challenge PactumJS comes with a concept ofData Store to pass data between API calls across tests.

Let's look at the test first.

awaitpactum.spec().post('/api/orders').withJson({"product":"PlayStation 5"}).expectStatus(200).stores('OrderID','id');
Enter fullscreen modeExit fullscreen mode

The above test will make aPOST request to/api/orders with givenjson payload and once the response is received it expects the status should be200 andstores the value ofid into a special variable calledOrderID which is internal to PactumJS.

Step 2 - Make Payment

The next step is to make the payment. Now the user makes aPOST request to/api/payments with the following payload.

Request Payload
{"order_id":"1f4c99e9-12df-45d4-b455-98418f4e3b1e","card_info":{"number":"1111-1111-1111-1111","expiry":"11/11","cvv":"111"}}
Enter fullscreen modeExit fullscreen mode

Now the API responds with the following response body which contains paymentid.

Response
{"id":"a32fce50-d4e8-4d95-b16f-57fd13fbb7df"}
Enter fullscreen modeExit fullscreen mode

Now let's talk about the test case.

As you observed, theorder id from the previous request is included in the request payload.

To get the value of special internal variable, PactumJS uses a special pattern -$S{<variable-name>} to access it.

Let's look at the test.

awaitpactum.spec().post('/api/payments').withJson({"order_id":"$S{OrderID}","card_info":{"number":"1111-1111-1111-1111","expiry":"11/11","cvv":"111"}}).expectStatus(200).stores('PaymentID','id');
Enter fullscreen modeExit fullscreen mode

PactumJS will internally replace$S{OrderID} with1f4c99e9-12df-45d4-b455-98418f4e3b1e before making the request.

In the above test case we are also saving the paymentid into the special variablePaymentId using thestores method. Using the paymentid we can track the status of the payment. So this brings us to the final step of our integration test.

Step 3 - Wait for Payment to be completed.

To get the status of the payment, user makes aGET request to the/api/payments/{payment_id} endpoint.

The API responds with the following response body.

Response
{"status":"in-progress"}
Enter fullscreen modeExit fullscreen mode

As you see, the status is stillin-progress. We need to wait for few seconds for the payment to be completed.

Including hard waits is a bad practice in testing. PactumJS comes with a concept ofretry mechanism which retries on failed expectations. It is similar tofluent wait in selenium.

Let's look at the test case.

awaitpactum.spec().get('/api/payments/{id}').withPathParams('id','$S{PaymentID}').expectStatus(200).expectJson({"status":"completed"}).retry();
Enter fullscreen modeExit fullscreen mode

By default it retries3 times with a delay of1000ms between each retry.

Complete Test

Now let's take a look at the entire test usingPactumJS andmocha.

constpactum=require('pactum');

it('order PS5 and make payment',async()=>{
awaitpactum.spec()
.post('/api/orders')
.withJson({
"product":"PlayStation 5"
})
.expectStatus(200)
.stores('OrderID','id');

awaitpactum.spec()
.post('/api/payments')
.withJson({
"order_id":"$S{OrderID}",
"card_info":{
"number":"1111-1111-1111-1111",
"expiry":"11/11",
"cvv":"111"
}
})
.expectStatus(200)
.stores('PaymentID','id');

awaitpactum.spec()
.get('/api/payments/{id}')
.withPathParams('id','$S{PaymentID}')
.expectStatus(200)
.expectJson({
"status":"completed"
})
.retry();

});

Enter fullscreen modeExit fullscreen mode




Conclusion

Writing readable and maintainable tests is very important to make API testing productive and enjoyable experience.

PactumJS abstracts the challenging parts to write tests in an easy and fun way and ultimately making API Integration testing super easy.

Top comments(3)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
cod3ddy profile image
Cod3ddy
  • Location
    Mzuzu, Malawi
  • Joined

Nice, I should try out pactum and see what other features it has

CollapseExpand
 
vladwulf profile image
Vladimir Agaev
  • Location
    London
  • Joined

I've recently tried pactum with NestJs and loved it a lot!
Thank you for the article

CollapseExpand
 
asaianudeep profile image
Anudeep
#javascript #testing #opensource #pactumjs
  • Joined

Awesome! Great to hear! Thank you for taking the time to write back.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

#javascript #testing #opensource #pactumjs
  • Joined

More fromAnudeep

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp