RESTful-API接口python自动化测试:增查改删

一般来说,增删改查的测试可以作为一个流程,那么删除就要放到最后测,因此称为增查改删。

以数据集的增查改删除为例简单了解一下业务,通过数据库建表来了解我们需要的操作。

Mongodb的python mongoengine ORM建表

  1 # -*- coding: utf-8 -*-
  2 
  3 import datetime
  4 from flask_mongoengine import MongoEngine
  5 from mongoengine import signals
  6 import helper
  7 
  8 db = MongoEngine()
  9 
 10 
 11 class ProductAttribute(db.EmbeddedDocument):
 12     k = db.StringField(required=True, max_length=50)
 13     v = db.StringField(required=True, max_length=100)
 14 
 15     meta = {
 16         'indexes': [
 17             {
 18                 'fields': ['k', 'v'],
 19                 'unique': True
 20             }
 21         ]
 22     }
 23 
 24 
 25 class Dataset(db.Document):
 26     name = db.StringField(required=True, max_length=50)
 27     type = db.StringField(max_length=20)
 28     x_consumer_custom_id = db.StringField()
 29 
 30     description = db.StringField(max_length=500)
 31     status = db.StringField(required=True, max_length=50, default="created")
 32 
 33     created_at = db.DateTimeField(required=True, default=datetime.datetime.utcnow)
 34     updated_at = db.DateTimeField(required=True)
 35     deleted_at = db.DateTimeField(default=None)
 36 
 37     meta = {
 38         'indexes': [
 39             {
 40                 'fields': ['name', 'x_consumer_custom_id'],
 41                 'unique': True
 42             }
 43         ]
 44     }
 45 
 46     def to_dict(self):
 47         return helper.mongo_to_dict(self, [])
 48 
 49 
 50 class ImageItem(db.Document):
 51     image_id = db.StringField(required=True, max_length=50)
 52     uri = db.URLField()
 53     title = db.StringField(required=True, max_length=50)
 54 
 55     description = db.StringField(max_length=500)
 56     status = db.StringField(required=True, max_length=50, default="created")
 57 
 58     created_at = db.DateTimeField(required=True, default=datetime.datetime.utcnow)
 59     updated_at = db.DateTimeField(required=True)
 60 
 61     meta = {
 62         'indexes': [
 63             {
 64                 'fields': ['image_id'],
 65                 'unique': True
 66             }
 67         ]
 68     }
 69 
 70     def to_dict(self):
 71         return helper.mongo_to_dict(self, [])
 72 
 73 
 74 class ProductItem(db.Document):
 75     product_id = db.StringField(required=True, max_length=50)
 76     name = db.StringField(required=True, max_length=100)
 77     category = db.StringField(required=True, max_length=50)
 78 
 79     description = db.StringField(max_length=500)
 80     status = db.StringField(required=True, max_length=50, default="created")
 81     shelf = db.StringField(required=True, max_length=50, default="on")
 82 
 83     images = db.ListField(db.URLField())
 84 
 85     attributes = db.EmbeddedDocumentListField(ProductAttribute)
 86 
 87     created_at = db.DateTimeField(required=True, default=datetime.datetime.utcnow)
 88     updated_at = db.DateTimeField(required=True)
 89 
 90     meta = {
 91         'indexes': [
 92             {
 93                 'fields': ['product_id'],
 94                 'unique': True
 95             }
 96         ]
 97     }
 98 
 99     def to_dict(self):
100         return helper.mongo_to_dict(self, [])
101 
102 
103 def update_timestamp(sender, document, **kwargs):
104     document.updated_at = datetime.datetime.utcnow()
105 
106 signals.pre_save.connect(update_timestamp, sender=Dataset)
107 signals.pre_save.connect(update_timestamp, sender=ProductItem)
108 signals.pre_save.connect(update_timestamp, sender=ImageItem)
mongodb tables

简单工程目录如下:

一  配置文件settings.py

 1 # coding=utf-8
 2 
 3 # HOST_PORT = "192.168.1.142:80"
 4 # HOST_PORT = "http://127.0.0.1:5000"
 5 # HOST_PORT = "http://47.92.xxx.7:80"
 6 HOST_PORT = "http://127.0.0.1:80"
 7 X_CONSUMER_CUSTOM_ID = "victor100"
 8 
 9 DATASET_NAME = "dataset100"
10 PRODUCT_ID = "product108"
11 
12 QUERY_PREFIX = "dataset"
13 PRODUCT_QUERY_PREFIX = "dataset"
14 
15 # 要先把这几个产品创建了
16 PRODUCT_IDS = ['product100', 'product101', 'product102']
17 SHELF = 'on'
18 
19 
20 CONTENT_TYPE = "application/json"
21 REPORT_FILE_NAME = "dataset_report.txt"
22 
23 
24 # 数据集增查改删
25 #
26 POST_URL = HOST_PORT + '/datasets'
27 #
28 GET_URL = POST_URL + '/{dataset_name}'.format(dataset_name=DATASET_NAME)
29 #
30 PATCH_URL = GET_URL
31 #
32 DELETE_URL = GET_URL
33 # 列表查
34 GET_LIST_URL = POST_URL
35 
36 # 商品集增查改删
37 #
38 POST_PRODUCT_URL = HOST_PORT + '/datasets' + '/{dataset_name}/items'.format(dataset_name=DATASET_NAME)
39 #
40 GET_PRODUCT_URL = POST_PRODUCT_URL + '/{item_id}'.format(item_id=PRODUCT_ID)
41 #
42 PATCH_PRODUCT_URL = GET_PRODUCT_URL
43 PATCH_PRODUCTS_URL = POST_PRODUCT_URL
44 #
45 DELETE_PRODUCT_URL = GET_PRODUCT_URL
46 # 列表查
47 GET_LIST_PRODUCT_URL = POST_PRODUCT_URL
settings.py

二 增加一个数据集

 1 # coding=utf-8
 2 import requests
 3 import json
 4 import sys
 5 from datasets_api_test.config.settings import X_CONSUMER_CUSTOM_ID, CONTENT_TYPE, DATASET_NAME, POST_URL
 6 from datasets_api_test.report.utils import generate_report
 7 
 8 stage = """创建一个数据集"""
 9 
10 try:
11     headers = {}
12     headers["x-consumer-custom-id"] = X_CONSUMER_CUSTOM_ID
13     headers["Content-Type"] = CONTENT_TYPE
14 
15     payload = {}
16     payload['dataset'] = {}
17     payload['dataset']['name'] = DATASET_NAME
18     payload['dataset']['type'] = "product"
19     payload['dataset']['description'] = "description001"
20     print(payload)
21 
22     resp = requests.post(url=POST_URL, json=payload, headers=headers)
23     print(resp.status_code)
24     print(resp.content)
25 except Exception as e:
26     print(e)
27 
28 
29 generate_report(stage, POST_URL, headers, resp.status_code, resp.content, data=payload)

三 查询一个数据集

# coding=utf-8
import requests
import json
import time
from datasets_api_test.config.settings import X_CONSUMER_CUSTOM_ID, GET_URL
from datasets_api_test.report.utils import generate_report

stage = """查询一个数据集"""

try:
    headers = {}
    headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

    resp = requests.get(url=GET_URL, headers=headers)
    print(resp.status_code)
    print(resp.content)
except Exception as e:
    print(e)

generate_report(stage, GET_URL, headers, resp.status_code, resp.content, data=None)

四 修改一个数据集

# coding=utf-8
import requests
import json
from datasets_api_test.config.settings import X_CONSUMER_CUSTOM_ID, CONTENT_TYPE, DATASET_NAME, PATCH_URL
from datasets_api_test.report.utils import generate_report

stage = """修改一个数据集"""

try:
    headers = {}
    headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

    para = {}
    para['dataset'] = {}
    para['dataset']['name'] = DATASET_NAME
    para['dataset']['description'] = 'description00000001'
    print(para)

    resp = requests.patch(url=PATCH_URL, json=para, headers=headers)
    print(resp.status_code)
    print(resp.content)
except Exception as e:
    print(e)

generate_report(stage, PATCH_URL, headers, resp.status_code, resp.content, data=para)

五 查询一个数据集列表

# coding=utf-8
import requests
import json
import time
from datasets_api_test.config.settings import X_CONSUMER_CUSTOM_ID, GET_LIST_URL, QUERY_PREFIX
from datasets_api_test.report.utils import generate_report

stage = """查询一个数据集list列表"""

try:
    headers = {}
    headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID
    para = {}
    para['query'] = QUERY_PREFIX
    para['page'] = 1
    para['per_page'] = 20
    para['order'] = 'desc'
    para['state'] = 'created'

    resp = requests.get(url=GET_LIST_URL, params=para, headers=headers)
    print(resp.status_code)
    print(resp.content)

except Exception as e:
    print(e)

generate_report(stage, GET_LIST_URL, headers, resp.status_code, resp.content, data=para)

六 删除一个数据集

# coding=utf-8
import requests
import json
from datasets_api_test.config.settings import X_CONSUMER_CUSTOM_ID, DELETE_URL
from datasets_api_test.report.utils import generate_report

stage = """删除一个数据集"""

try:
    headers = {}
    headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

    resp = requests.delete(url=DELETE_URL, headers=headers)
    print(resp.status_code)
    print(resp.content)
except Exception as e:
    print(e)


generate_report(stage, DELETE_URL, headers, resp.status_code, resp.content, data=None)

七 程序主入口

上面的结果我都写入了一个简单报告:

 1 # coding=utf-8
 2 import os
 3 from datasets_api_test.config.settings import REPORT_FILE_NAME
 4 
 5 def generate_report(stage, URL, headers, status_code, content, data=None):
 6     file_dir = os.path.dirname(os.path.abspath(__file__))
 7     file_name = REPORT_FILE_NAME
 8     file_path = os.path.join(file_dir, file_name)
 9     print(file_path)
10     with open(file_path, 'a+') as f:
11         f.write('--------------------------------------\n')
12         f.write(stage + '\n')
13         f.write('请求部分' + '\n')
14         f.write(URL + '\n')
15         f.write(str(headers) + '\n')
16         f.write(str(data) + '\n')
17         f.write('\n')
18         f.write('响应部分' + '\n')
19         f.write(str(status_code) + '\n')
20         f.write(content)
21         f.write('--------------------------------------\n')
22 
23 
24 def generate_shell(path_list):
25     file_dir = os.path.dirname(os.path.abspath(__file__))
26     file_name = "start.sh"
27     file_path = os.path.join(file_dir, file_name)
28     print(file_path)
29     with open(file_path, 'w+') as f:
30         f.write("#!/bin/bash" + '\n')
31         for line in path_list:
32             f.write("python" + " " + line + '\n')
33 
34     return file_path
utils.py

下面是主程序

# coding=utf-8

import os
import sys
import subprocess

base_path = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,base_path)
print(sys.path)

from datasets_api_test.report.utils import generate_shell

if __name__ == '__main__':

    dataset_base = os.path.join(base_path, 'datasets')
    product_base = os.path.join(base_path, 'product_item')
    dataset_list = ['post_datasets_item.py', 'get_datasets_item.py', 'patch_datasets_item.py', 'get_datasets_list.py']
    product_list = ['post_product_item.py', 'get_product_item.py', 'patch_product_item.py', 'get_product_list.py',]
    dp_list = ['delete_product_item.py']
    dd_list = ['delete_datasets_item.py']

    dataset_list_new = [os.path.join(dataset_base, i) for i in dataset_list]
    product_list_new = [os.path.join(product_base, i) for i in product_list]
    dp_list_new = [os.path.join(product_base, i) for i in dp_list]
    dd_list_new = [os.path.join(dataset_base, i) for i in dd_list]

    dataset_list_new.extend(product_list_new)

    # 如果不要删除新生的测试数据库的数据集和商品集表,就注释掉下面2行
    dataset_list_new.extend(dp_list_new)
    dataset_list_new.extend(dd_list_new)
    print(dataset_list_new)

    shell_file = generate_shell(dataset_list_new)
    os.system('sh %s'%(shell_file))
main.py

这只是一个自己写的简单的测试小框架,但是应该用更加规范的写法来自动化测试。

八 自动化的接口测试

利用requests来进行接口测试 + unittest进行用例管理 + HTMLTextRunner自动生成html测试报告 + smtp进行邮件发送 + Jenkins进行持续集成

直接集成到test_process.py

# coding=utf-8
from __future__ import print_function
import unittest
import requests
from HTMLTestRunner import HTMLTestRunner


from config.settings import X_CONSUMER_CUSTOM_ID, DATASET_NAME, PRODUCT_ID, CONTENT_TYPE, REPORT_FILE_NAME, \
    POST_URL, GET_URL, PATCH_URL, DELETE_URL, GET_LIST_URL, POST_PRODUCT_URL, GET_PRODUCT_URL, PATCH_PRODUCT_URL, \
    DELETE_PRODUCT_URL, GET_LIST_PRODUCT_URL, QUERY_PREFIX
from core.utils import generate_report

from log.logger import logger

class DatasetsAPITest(unittest.TestCase):

    def tearDown(self):
        logger.info('tear down...')

    def setUp(self):
        logger.info('tear...up')

    def test_post_datasets_item(self):

        stage = """创建一个数据集"""
        try:
            headers = {}
            headers["x-consumer-custom-id"] = X_CONSUMER_CUSTOM_ID
            headers["Content-Type"] = CONTENT_TYPE

            payload = {}
            payload['dataset'] = {}
            payload['dataset']['name'] = DATASET_NAME
            payload['dataset']['type'] = "product"
            payload['dataset']['description'] = "description001"


            resp = requests.post(url=POST_URL, json=payload, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, POST_URL, headers, resp.status_code, resp.content, data=payload)

        self.assertEquals(10, 10)

    def test_get_datasets_item(self):

        stage = """查询一个数据集"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

            resp = requests.get(url=GET_URL, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, GET_URL, headers, resp.status_code, resp.content, data=None)

    def test_patch_datasets_item(self):

        stage = """修改一个数据集"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

            para = {}
            para['dataset'] = {}
            para['dataset']['name'] = DATASET_NAME
            para['dataset']['description'] = 'description00000001'
            logger.info(para)

            resp = requests.patch(url=PATCH_URL, json=para, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, PATCH_URL, headers, resp.status_code, resp.content, data=para)

    def test_get_datasets_list(self):

        stage = """查询一个数据集list列表"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID
            para = {}
            para['query'] = QUERY_PREFIX
            para['page'] = 1
            para['per_page'] = 20
            para['order'] = 'desc'
            para['state'] = 'created'

            resp = requests.get(url=GET_LIST_URL, params=para, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)

        except Exception as e:
            logger.error(e)

        generate_report(stage, GET_LIST_URL, headers, resp.status_code, resp.content, data=para)

    def test_post_product_item(self):

        stage = """创建一个商品集"""
        try:
            headers = {}
            headers["x-consumer-custom-id"] = X_CONSUMER_CUSTOM_ID
            headers["Content-Type"] = CONTENT_TYPE

            payload = {}
            payload['item'] = {}
            payload['item']['product_id'] = PRODUCT_ID
            payload['item']['name'] = DATASET_NAME

            payload['item']['description'] = "description0000000000"
            payload['item']['category'] = "category0000000"
            # payload['attributes'] = [dict(k="hello", v="world"), dict(k="hello1", v="world1")]
            payload['item']['attributes'] = [{'k': "hello", 'v': 'world'}, {'k': "hello1", 'v': 'world2'}]
            payload['item']['images'] = ['http://www.baidu.com/hello', 'http://www.baidu.com/world']
            logger.info(payload)

            resp = requests.post(url=POST_PRODUCT_URL, json=payload, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, POST_PRODUCT_URL, headers, resp.status_code, resp.content, payload)

    def test_get_product_item(self):

        stage = """查询一个商品集"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

            resp = requests.get(url=GET_PRODUCT_URL, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, GET_PRODUCT_URL, headers, resp.status_code, resp.content, data=None)

    def test_patch_product_item(self):

        stage = """修改一个商品集"""
        try:
            headers = {}
            headers["x-consumer-custom-id"] = X_CONSUMER_CUSTOM_ID
            headers["Content-Type"] = CONTENT_TYPE

            payload = {}
            payload['item'] = {}
            payload['item']['product_id'] = PRODUCT_ID
            payload['item']['name'] = DATASET_NAME

            payload['item']['description'] = "ssss"
            payload['item']['category'] = "cate003"
            payload['item']['attributes'] = [{"k": "hello", "v": "world"}]
            payload['item']['images'] = ['http://www.baidu.com/hello', 'http://www.baidu.com/world']
            logger.info(payload)

            resp = requests.patch(url=PATCH_PRODUCT_URL, json=payload, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, PATCH_PRODUCT_URL, headers, resp.status_code, resp.content, payload)

    def test_get_product_list(self):

        stage = """查询一个商品集列表"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

            para = {}
            para['page'] = 1
            para['per_page'] = 20
            para['order'] = 'desc'
            para['status'] = 'created'

            resp = requests.get(url=GET_LIST_PRODUCT_URL, params=para, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, GET_LIST_PRODUCT_URL, headers, resp.status_code, resp.content, data=para)

    def test_delete_product_item(self):

        stage = """删除一个商品集"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

            resp = requests.delete(url=DELETE_PRODUCT_URL, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, DELETE_PRODUCT_URL, headers, resp.status_code, resp.content, data=None)

    def test_delete_datasets_item(self):

        stage = """删除一个数据集"""
        try:
            headers = {}
            headers['x-consumer-custom-id'] = X_CONSUMER_CUSTOM_ID

            resp = requests.delete(url=DELETE_URL, headers=headers)
            logger.info(resp.status_code)
            logger.info(resp.content)
        except Exception as e:
            logger.error(e)

        generate_report(stage, DELETE_URL, headers, resp.status_code, resp.content, data=None)

 而进行的主函数就是:

# coding=utf-8
from __future__ import absolute_import
import unittest
from core.test_process import DatasetsAPITest
from HTMLTestRunner import HTMLTestRunner


if __name__ == '__main__':

    # 打乱了我的流程顺序
    # test_dir = './core/'
    # discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

    func_list = [DatasetsAPITest('test_post_datasets_item'),
                 DatasetsAPITest('test_get_datasets_item'),
                 DatasetsAPITest('test_patch_datasets_item'),
                 DatasetsAPITest('test_get_datasets_list'),
                 DatasetsAPITest('test_post_product_item'),
                 DatasetsAPITest('test_get_product_item'),
                 DatasetsAPITest('test_patch_product_item'),
                 DatasetsAPITest('test_get_product_list'),
                 DatasetsAPITest('test_delete_product_item'),
                 DatasetsAPITest('test_delete_datasets_item')
                 ]
    my_test_suite = unittest.TestSuite()
    my_test_suite.addTests(func_list)

    fp = file('dataset_report.html', 'wb')
    runner = HTMLTestRunner.HTMLTestRunner(
        stream=fp,
        title='Datasets API Test',
        description='This demonstrates the report output by HTMLTestRunner.'
    )
    runner.run(my_test_suite)

这些自动化测试完全可以集成到CI中去。

 

posted @ 2018-09-29 11:58  Adamanter  阅读(1288)  评论(0编辑  收藏  举报