用Postman实现API测试自动化的教程

202 阅读10分钟

API是你作为一个开发者建立的几乎每一个应用程序背后的驱动力,作为两个或多个软件组件之间的通信渠道。

然而,这种类型的系统的后果是,一个组件的失败会对依赖它的其他组件产生重大影响。因此,广泛地测试你的API以确保你的应用程序的正确性和可预测性是至关重要的。

有许多不同的方法可以测试你的API,无论你选择哪种方法或方法的组合,最终都取决于你当前的业务需求、可用资源和实施细节。

在这篇文章中,我们将探讨如何为你的API编写自动化的功能和集成测试,并在CI/CD管道中运行:

为什么要将API测试自动化?

编写测试有助于确保你的应用程序在任何时候的可预测性和正确性。因此,你应该在你的代码库发生变化时经常运行测试。像这样的重复性任务往往是自动化的好人选。

自动化测试使你有信心对你的应用程序进行修改和添加新的功能,因为你总是可以依靠你的测试来指出你可能已经引入的错误。

用Postman编写API测试

Postman是一个平台,为构建、测试、记录和模拟API提供了一套完整的工具。作为一个开发者,你很可能在本地开发时使用Postman向你的后端应用程序发出请求,但你可以用它做得更多。

设置Postman

要继续学习本教程,你需要一个Postman账户。如果你还没有,创建一个免费账户。然后,导航到你的Postman工作区,开始工作。

我们将创建一个名为Delivery-API Tests 的新集合,在那里我们将为我们在本节后面创建的交付API编写一些功能和集成测试。功能测试检查单个API端点的行为,确保请求-响应周期符合预期。另一方面,集成测试检查可以由两个或多个端点组成的具体流程,以确定参与用户流程的不同组件是否按照预期工作。

在这一点上,你的工作区应该在左边的面板上显示集合。

Postman Workspace Collection

设置请求

接下来,我们需要创建请求,以容纳我们的测试。一个请求将代表一个API端点。在Delivery-API Tests 集合上,点击出现在右边的菜单按钮。

选择添加请求,并将创建的请求命名为Search Deliveries 。再创建三个请求,分别命名为Select Delivery,Confirm Pickup, 和Complete Delivery

现在,我们需要为每个请求编写测试。Postman有一个内置的测试工具,允许你使用JavaScript语法编写测试。测试在一个请求运行后立即执行,你可以在测试脚本中访问从请求返回的响应。

Delivery-API Tests 集合中,选择 **Search Deliveries**请求,并选择测试标签。将以下代码块粘贴到编辑器中。

const responseJson = pm.response.json()

pm.test("response status", function() {
    pm.response.to.have.status(200)
})

pm.test("data contains results", function() {
    pm.expect(responseJson).to.haveOwnProperty("data")
    pm.expect(responseJson.data).to.be.an("array")
    pm.expect(responseJson.data[0]).to.haveOwnProperty("status")
})

pm.collectionVariables.set("SELECTED_DELIVERY_ID", responseJson.data[0].id)

在上面的代码中,我们通过调用pm.response.json() 获得JSON格式的响应。注意,pm 是一个全局对象,在所有的请求脚本中都可用。然后我们使用pm.test 定义了两个测试用例。

如果你熟悉JavaScript的测试,那么这里的语法应该是很简单的。Postman支持Chai断言库的语法,所以你可以用你已经在JavaScript中使用的相同方式来编写测试。

在测试案例中,我们要检查正确的状态代码、返回的数据类型和一些额外的必填字段。这些都是简单的测试,但目的是了解Postman中测试的概念。

请注意,在代码块的最后一行,我们正在设置一个名为SELECTED_DELIVERY_ID 的集合变量。集合变量是一种直观的方式,可以在不同的请求中共享数据。

接下来,我们要为其他的请求编写测试。将下面的代码块粘贴到相应的请求中。

// Select Delivery
const responseJson = pm.response.json()

pm.test("response status", function() {
    pm.response.to.have.status(200)
})

pm.test("data contains result", function() {
    pm.expect(responseJson).to.haveOwnProperty("data")
    pm.expect(responseJson.data).to.be.an("object")
    pm.expect(responseJson.data).to.haveOwnProperty("status")
    pm.expect(responseJson.data.status).to.eql("QUEUED")
})


// Confirm Pickup
const responseJson = pm.response.json()

pm.test("response status", function() {
    pm.response.to.have.status(200)
})

pm.test("data contains result", function() {
    pm.expect(responseJson).to.haveOwnProperty("data")
    pm.expect(responseJson.data).to.be.an("object")
    pm.expect(responseJson.data).to.haveOwnProperty("status")
    pm.expect(responseJson.data.status).to.eql("PICKED_UP")
})


// Complete Delivery
const responseJson = pm.response.json()

pm.test("response status", function() {
    pm.response.to.have.status(200)
})

pm.test("data contains result", function() {
    pm.expect(responseJson).to.haveOwnProperty("data")
    pm.expect(responseJson.data).to.be.an("object")
    pm.expect(responseJson.data).to.haveOwnProperty("status")
    pm.expect(responseJson.data.status).to.eql("COMPLETED")
})

除了对status 字段的断言外,其他请求的测试案例是相同的。现在我们有了对请求的测试,让我们来运行它们。我们需要创建一个后端服务器来处理API请求。你可以用任何语言或框架实现后端服务器,只要它符合REST标准,但在本文中,我们将使用Koa建立一个简单的Node.js服务器。

构建API服务器

在你的终端,创建一个文件夹,用Yarn或npm初始化一个Node.js项目。

$ mkdir delivery-api
$ cd delivery-api
$ yarn init -y 

现在,创建一个名为app.js 的文件,并安装必要的依赖项。

$ touch app.js
$ yarn add koa @koa/router

在你的package.json 文件中,添加以下脚本。

//...
  "scripts": {
    "start": "node app.js"
  },
//...

Koa是Node.js的一个轻量级HTTP中间件框架,与Express类似。让我们初始化一个Koa服务器并定义与我们在Postman中设置的请求相对应的路由处理程序。在你的app.js 文件中,粘贴下面的代码块。

const Koa = require("koa");
const Router = require("@koa/router");
const app = new Koa();
const router = new Router();

app.use(router.routes());

const deliveries = [
   {
      id: "1",
      pickupAddress: "1000 4th Ave, Seattle, WA, 98104",
      pickupPhoneNumber: "+14148928000",
      dropoffAddress: "1201 3rd Ave, Seattle, WA, 98101",
      dropoffPhoneNumber: "+14148928000",
      instructions: "",
      status: "CREATED",
   },
   {
      id: "2",
      pickupAddress: "1000 4th Ave, Seattle, WA, 98104",
      pickupPhoneNumber: "+14148915000",
      dropoffAddress: "1201 3rd Ave, Seattle, WA, 98101",
      dropoffPhoneNumber: "+14148915000",
      instructions: "",
      status: "CREATED",
   },
];

router.get("/deliveries", (ctx) => {
   ctx.body = {
      status: "00",
      message: "successs",
      data: deliveries,
   };
});

router.get("/deliveries/:id/select", (ctx) => {
   const id = ctx.params["id"];
   const delivery = deliveries.find((obj) => obj.id === id);
   if (!delivery) {
      ctx.body = {
         status: "01",
         message: "not found",
         data: null,
      };
   }
   ctx.body = {
      status: "00",
      message: "successs",
      data: { ...delivery, status: "QUEUED" },
   };
});

router.get("/deliveries/:id/confirm-pickup", (ctx) => {
   const id = ctx.params["id"];
   const delivery = deliveries.find((obj) => obj.id === id);
   if (!delivery) {
      ctx.body = {
         status: "01",
         message: "not found",
         data: null,
      };
   }
   ctx.body = {
      status: "00",
      message: "successs",
      data: { ...delivery, status: "PICKED_UP" },
   };
});

router.get("/deliveries/:id/complete", (ctx) => {
   const id = ctx.params["id"];
   const delivery = deliveries.find((obj) => obj.id === id);
   if (!delivery) {
      ctx.body = {
         status: "01",
         message: "not found",
         data: null,
      };
   }
   ctx.body = {
      status: "00",
      message: "successs",
      data: { ...delivery, status: "COMPLETED" },
   };
});

app.listen(8000);

这里有很多事情要做,所以让我们把它分解。首先,我们初始化一个新的Koa应用程序和一个新的Router 对象。使用router 实例,我们定义四条路径,这些路径与我们在Postman中创建的请求相匹配。最后,我们通过调用app.listen() 来启动服务器。

综上所述,这个简单的API服务器试图模拟一个送餐应用的订单交付过程。现在,通过在你的终端运行yarn start 来启动该服务器。

在Postman上运行手动测试

现在,我们已经为运行测试做好了一切准备。如果你在网络上使用Postman,你将无法连接到localhost 。然而,有两种方法可以解决这个问题。你可以下载Postman桌面应用程序或使用ngrok作为隧道,将你的localhost 端口暴露在互联网上。

如果你决定使用ngrok,你需要做的就是安装它并启动一个指向你服务器的隧道。打开另一个终端实例,然后运行以下命令并复制显示的URL。

$ ngrok http 8000

该URL应该类似于 [https://3d43-154-130-109-210.ngrok.io](https://3d43-154-130-109-210.ngrok.io).导航到Postman,无论是在网络上还是在桌面上,选择 **Delivery-API Tests**集合,并打开变量标签。

API_BASE_URL 键添加一个变量,并将其值设置为 [http://localhost:8000](http://localhost:8000)或ngrok URL,如果你没有使用Postman桌面。在添加一个新的变量时,一定要点击Persist All,以确保外部服务可以访问它。

Postman Variables Delivery API Tests

现在,我们可以对每个请求使用集合变量。将每个请求的URL字段更新为以下值。

  • Search Deliveries:{{API_BASE_URL}}/deliveries?page=1&count=20
  • Select Delivery:{{API_BASE_URL}}/deliveries/:id/select
  • Confirm Pickup:{{API_BASE_URL}}/deliveries/:id/confirm-pickup
  • Complete Delivery:{{API_BASE_URL}}/deliveries/:id/complete

我们可以使用两种方法中的一种手动运行我们的测试。第一种是单独运行请求,让每个请求的测试脚本被执行。另外,我们可以使用集合运行器一次运行所有的集合。我们将在下一节中使用集合运行器,但你可以通过点击发送按钮临时手动运行每个请求。

当你运行一个请求时,你会在底部面板上看到响应,但你也可以通过点击底部面板上的测试结果标签来看到测试结果。

Postman Test Results Tab

这就是你在Postman中运行一个测试所需要做的。然而,每当你对代码库进行修改时,都要访问你的Postman工作区并运行测试,这感觉很不直观。这种方法与开发工作流程不一致,所以让我们来改进它。

自动化你的API测试

在本节中,我们将通过自动化工作流程使测试过程更直观,更省时。优化的开发工作流程包括进行本地修改并将新功能推送到源码控制,在那里它们会被CI/CD管道接收,触发一些构建或部署任务。

Postman提供了一个名为Newman的命令行工具,让你从CLI运行集合。它还提供了与CI/CD环境的无缝集成,这意味着我们可以在部署步骤中设置我们的测试来运行。这大大简化了测试过程,避免了我们在工作区不断运行测试。

将Newman与GitHub动作集成

我们可以在许多持续集成服务中设置Newman。在这篇文章中,我们将使用GitHub Actions。让我们先为Newman定义一个工作流。在你的delivery-api 项目中,运行以下命令。

$ mkdir .github
$ mkdir .github/workflows
$ touch .github/workflows/postman-tests.yml

postman-tests.yml 文件中添加以下工作流定义:

# postman-tests.yml
name: Newman Run
on:
  push:
    branches:
      - main
  # types: [closed]
jobs:
  newman:
    name: Postman-tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Install Node
        uses: actions/setup-node@v3
        with:
          node-version: 14
      - name: Install Newman & Reporter
        run: |
          npm install -g newman
          npm install -g newman-reporter-htmlextra
      # Make directory for test results in workspace
      - name: Make Directory
        run: mkdir -p newman-results
      # Run newman cli
      - name: Run Newman
        env:
          POSTMAN_API_URL: 'https://api.getpostman.com'
          POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}
          POSTMAN_COLLECTION_UID: ${{ secrets.POSTMAN_COLLECTION_UID }}
        run: |
          newman run "${{env.POSTMAN_API_URL}}/collections/${{env.POSTMAN_COLLECTION_UID}}?apikey=${{env.POSTMAN_API_KEY}}" \
          -r htmlextra,cli --reporter-htmlextra-export newman-results/htmlreport.html
      # Upload test results to workspace
      - name: Upload Results
        uses: actions/upload-artifact@v3
        with:
          name: Postman_Test_Reports
          path: newman-results

上面的代码是一个简单的工作流,当我们推送到仓库时,特别是在默认的main 分支上运行。我们为Postman测试定义了一个有一系列步骤的工作。

首先,我们运行签出动作,然后我们使用预先定义的动作actions/setup-node@v3 ,安装Node.js。接下来,我们安装Newman和newman-reporter-htmlextra 。报告者是Newman的一个插件,可以生成HTML格式的测试摘要。然后我们用一些参数运行Newman CLI工具,包括我们的集合的Postman API URL。

注意,我们已经定义了一些环境变量。POSTMAN_API_KEYPOSTMAN_COLLECTION_UID 是从GitHub行动秘密中提取的。在设置这些秘密之前,我们需要创建一个存储库。最后,在运行Newman之后,我们使用预定义的动作actions/upload-artifact@v3 ,将报告者生成的HTML文件上传到我们以后可以访问的位置。

将所有的东西集中起来

最后,我们需要把项目推送到GitHub,并看到工作流的运行。导航到你的GitHub账户,创建一个名为delivery-api 的新仓库,并复制远程URL。接下来,我们将在项目中初始化 Git,添加远程 URL,提交我们的修改,然后推送修改:

$ git init -b main
$ git remote add origin <your-remote-url>
$ git add .
$ git commit "<message>"
$ git push -u origin main

如果你打开 GitHub 仓库中的Actions 标签,你应该看到工作流正在运行或已经失败。这是因为我们还没有添加秘钥。

为了解决这个问题,我们需要在Postman上生成一个API密钥,同时获取集合的UID。导航到你的Postman工作区;在顶部菜单栏,点击你的个人资料,选择设置。从侧面导航中选择API密钥,然后生成一个API密钥并复制该值。

接下来,向URL发出一个GET 请求 [https://api.getpostman.com/collections](https://api.getpostman.com/collections)的请求,并设置一个头,其中包含键x-api-key 和一个等于你生成的API密钥的值。你的响应应该包含一个你的集合的列表。

Get Request Response Collections

转到你的GitHub仓库,在GitHub行动秘密中添加POSTMAN_API_KEYPOSTMAN_COLLECTION_UIDPOSTMAN_COLLECTION_UID 是你的Delivery-API Tests 集合对象中的uid 字段。

Github Repository Postman API Keyy

现在,再次进入你的Actions 标签,尝试重新运行失败的作业。如果一切正常,你应该在Artifacts 面板上看到一个文件,这是工作流程中生成的报告。你可以下载并在你的浏览器中打开这个HTML文件。

Completed Postman Test Reports File

这就是了!我们已经成功地将我们的API测试自动化了。每次我们进行修改并推送到上游分支时,都会触发工作流,运行我们的测试。理想情况下,我们希望在部署后运行这个工作流,但为了保持简单,我们只定义了Postman测试的工作流。

Postman在API测试中的局限性

Postman是一个伟大的API测试工具,但是它也有自己的局限性。像软件中的其他东西一样,你要考虑你独特的项目需求,以确定工作的正确工具。首先要考虑的是你测试的范围和复杂性。如果你需要编写依赖于某些外部服务的测试,你可能不容易实现自动化。

另一个限制是灵活性。因为你在与你的应用逻辑所在的不同环境中编写测试,所以很难共享和重用代码片段。当你想针对多个不同的请求参数测试一个API端点时,这可能是特别令人沮丧的。Postman仍然是一个很好的测试工具,而作为一个开发者,你应该对使用它进行测试做出明智的决定。

总结

在这篇文章中,我们回顾了为什么测试你应用程序中的API很重要。我们探讨了使用Postman测试我们的API,包括设置Newman和GitHub Actions。最后,我们回顾了Postman在测试方面的一些限制。总的来说,Postman是一个用于构建、测试、记录和模拟API的伟大工具。我希望你喜欢这个教程,并祝你编码愉快!