接口测试 开源~自研接口测试平台 Django2+Bootstrap3+Unittest

转载  https://testerhome.com/topics/15657

 

python3.6.4 Django2.0 框架

文档更新

第一篇:https://testerhome.com/topics/13269 
第二篇:https://testerhome.com/topics/14801
第三篇:https://testerhome.com/topics/15352

版本更新

V1.8 引入mongo对于返回结果值存储,实现接口依赖功能。
V1.7 优化断言模块,采用json方法多层级遍历,增加断言比较方法
V 1.6 修复环境配置取消必须绑定端口号,接口测试取消必须连接数据库,优化定时模块
V 1.5 实现可选择邮箱发送
V 1.4 实现日志模块和报告数据分析模块
V 1.3 引入任务概念,实现定时模块(双环境)的控制
V 1.2 定义生成脚本规则,实现自动生成脚本,动态引入sql,增加unittest的失败重跑机制
V 1.1 实现配置化管理,环境配置,数据库配置,邮箱配置
V 1.0 实现用例步骤维护,实现3种http调用,引入django和unittest

数据库结构

 

登录模块

 

项目和模块页面

 

 

用例

用例中的用例名需要设置成英文,api不需要带上http://。
如果是状态为false的用例不支持任务添加,支持用例新增,修改,以及批量升级

 

 

步骤

一个用例对应多个步骤,步骤名需要使用中文,目前可以使用前3种方式请求。
信息头、参数、断言都可以使用变量,变量格式为${}
支持步骤新增,修改,以及批量升级

 

 

断言

断言例如可以采用['result']['data'][0]['id']这样的方式作为对返回值的获取,可采用的方法也有多种
当按钮关闭时表示不使用断言

 

接口依赖

一个步骤可以去依赖另一个步骤,可以多层级依赖,也可以选择依赖多个或被多个依赖,需要配置依赖那个步骤,依赖步骤返回值的路径(跟断言取值方法一致),以及变量名
当按钮关闭时表示不使用接口依赖

 

配置页面

 

 

 

生成脚本

在用例页面勾选对应的用例去生成任务,任务名设置为英文,对应的执行结果task目录下生成以任务名命名的文件夹,文件夹下testcase目录以及report目录,前者存放生成的脚本,后者生成日志和邮件报告

定时任务

如果选择单次执行,那么关闭定时任务就可以。定时任务input框可以点击进入,配置方法采用crontab。状态是配置了定时时间之后才去判断状态的,false表示不启动。

 

报告分析

5次内执行结果,失败数,断言失败数,成功数等等,也会将反馈和今日错误反馈给出。

 


这里有个地方需要配置,我默认用的message,如果你接口第一层返回值定义的是其他信息时,需要修改make_testcase.py的两个地方

安装步骤

依赖库安装:
Django 2.0.2
django-bootstrap3
pymysql,pymssql,DBUtils
Requests
bs4
apscheduler
pymongo
两个环境的前提,修改uniitest源码:
1.新增unittest的case.py文件中TestCase类加入一个方法

#自主添加的方法
    def chooseAssertWay(self,response,assertway,assert_response):
        if assertway=="assertEqual":
            self.assertEqual(response,assert_response)
        elif assertway=="assertNotEqual":
            self.assertNotEqual(response,assert_response)
        elif assertway=="assertRegexpMatches":
            self.assertRegexpMatches(response,assert_response)
        elif assertway=="assertNotRegexpMatches":
            self.assertNotRegexpMatches(response,assert_response)
        elif assertway=="assertGreater":
            self.assertGreater(response,assert_response)
        elif assertway=="assertGreaterEqual":
            self.assertGreaterEqual(response,assert_response)
        elif assertway=="assertLess":
            self.assertLess(response,assert_response)
        elif assertway=="assertLessEqual":
            self.assertLessEqual(response,assert_response)
        elif assertway=="assertIn":
            self.assertIn(response,assert_response)
        elif assertway=="assertNotIn":
            self.assertNotIn(response,assert_response)

2.更改unittest的loader.py文件中TestLoader类一个方法discover

def discover(self, start_dir,case_names_weights, pattern='test*.py', top_level_dir=None):
    """Find and return all test modules from the specified start
    directory, recursing into subdirectories to find them and return all
    tests found within them. Only test files that match the pattern will
    be loaded. (Using shell style pattern matching.)

    All test modules must be importable from the top level of the project.
    If the start directory is not the top level directory then the top
    level directory must be specified separately.

    If a test package name (directory with '__init__.py') matches the
    pattern then the package will be checked for a 'load_tests' function. If
    this exists then it will be called with (loader, tests, pattern) unless
    the package has already had load_tests called from the same discovery
    invocation, in which case the package module object is not scanned for
    tests - this ensures that when a package uses discover to further
    discover child tests that infinite recursion does not happen.

    If load_tests exists then discovery does *not* recurse into the package,
    load_tests is responsible for loading all tests in the package.

    The pattern is deliberately not stored as a loader attribute so that
    packages can continue discovery themselves. top_level_dir is stored so
    load_tests does not need to pass this argument in to loader.discover().

    Paths are sorted before being imported to ensure reproducible execution
    order even on filesystems with non-alphabetical ordering like ext3/4.
    """
    set_implicit_top = False
    if top_level_dir is None and self._top_level_dir is not None:
        # make top_level_dir optional if called from load_tests in a package
        top_level_dir = self._top_level_dir
    elif top_level_dir is None:
        set_implicit_top = True
        top_level_dir = start_dir

    top_level_dir = os.path.abspath(top_level_dir)

    if not top_level_dir in sys.path:
        # all test modules must be importable from the top level directory
        # should we *unconditionally* put the start directory in first
        # in sys.path to minimise likelihood of conflicts between installed
        # modules and development versions?
        sys.path.insert(0, top_level_dir)
    self._top_level_dir = top_level_dir

    is_not_importable = False
    is_namespace = False
    tests = []
    if os.path.isdir(os.path.abspath(start_dir)):
        start_dir = os.path.abspath(start_dir)
        if start_dir != top_level_dir:
            is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py'))
    else:
        # support for discovery from dotted module names
        try:
            __import__(start_dir)
        except ImportError:
            is_not_importable = True
        else:
            the_module = sys.modules[start_dir]
            top_part = start_dir.split('.')[0]
            try:
                start_dir = os.path.abspath(
                   os.path.dirname((the_module.__file__)))
            except AttributeError:
                # look for namespace packages
                try:
                    spec = the_module.__spec__
                except AttributeError:
                    spec = None

                if spec and spec.loader is None:
                    if spec.submodule_search_locations is not None:
                        is_namespace = True

                        for path in the_module.__path__:
                            if (not set_implicit_top and
                                not path.startswith(top_level_dir)):
                                continue
                            self._top_level_dir = \
                                (path.split(the_module.__name__
                                     .replace(".", os.path.sep))[0])
                            tests.extend(self._find_tests(path,
                                                          pattern,
                                                          namespace=True))
                elif the_module.__name__ in sys.builtin_module_names:
                    # builtin module
                    raise TypeError('Can not use builtin modules '
                                    'as dotted module names') from None
                else:
                    raise TypeError(
                        'don\'t know how to discover from {!r}'
                        .format(the_module)) from None

            if set_implicit_top:
                if not is_namespace:
                    self._top_level_dir = \
                       self._get_directory_containing_module(top_part)
                    sys.path.remove(top_level_dir)
                else:
                    sys.path.remove(top_level_dir)

    if is_not_importable:
        raise ImportError('Start directory is not importable: %r' % start_dir)

    if not is_namespace:
        tests = list(self._find_tests(start_dir, pattern))
    #print (tests)
    #正则提取用例名,排序
    regex=re.compile(r'testcase\.(.+?)\.')
    for i in range(0, len(tests) - 1):
        for j in range(2, len(tests) - 1 - i):
            try:
                if case_names_weights[regex.findall(str(tests[j]))[0]] > case_names_weights[regex.findall(str(tests[j+1]))[0]]:
                    c = tests[j]
                    tests[j] = tests[j + 1]
                    tests[j + 1] = c
            except:
                # 方法为空时不变
                pass
    return self.suiteClass(tests)

windows部署:
1.根据testhome安装python3.6和对应的python库(还需要添加HTMLTestRunner.py)
2.选择一个mysql数据库新建一个request数据库作为测试库,在django的setting.py文件的86行配置数据库的信息(ip,端口,数据库名称,用户名,密码)
3.选择一个mongo数据库作为测试库,在django的setting.py文件的103行配置数据库的信息(ip,端口,集合,一张表)
4.进入到项目根目录,数据库迁移:python manage.py makemigrations在request应用下的migrations目录下创建了一个 0001_initial.py 文件,执行python manage.py migrate,执行完成库表生成
5.创建第一个用户python manage.py createsuperuser
6.django的setting.py文件的28行,因为是本地启动保持ALLOWED_HOSTS = []就好了
7.配置编译器启动方式,选择django server启动,HOST填写127.0.0.1,port填写8000,运行
8.访问127.0.0.1:8000,能访问到就ok了

linux部署
1.根据testhome安装python3.6和对应的python库(还需要添加HTMLTestRunner.py)
2.把源代码放到linux下(我创建了pj目录,项目放在/home/pj下)
3.选择一个mysql数据库新建一个request数据库作为测试库,在django的setting.py文件的86行配置数据库的信息(ip,端口,数据库名称,用户名,密码)
4.选择一个mongo数据库作为测试库,在django的setting.py文件的103行配置数据库的信息(ip,端口,集合,一张表)
5.进入到项目根目录,数据库迁移:python manage.py makemigrations在request应用下的migrations目录下创建了一个 0001_initial.py 文件,执行python manage.py migrate,执行完成库表生成
6.创建第一个用户python manage.py createsuperuser,之后的用户登录http://192.168.100.158:8000/admin/去创建用户组和用户以及分配权限
7.在pj目录下创建logs目录,下面创建request.log文件存放项目日志文件
8.在django的setting.py文件的28行,添加自己linux的ip(我的是ALLOWED_HOSTS = ['192.168.100.158'])
9.把启动shell和关闭shell放在根目录下(requestnew),sh start.sh,项目就启动了;项目关闭则执行sh shutdown.sh
10.如果目录结构想要有所调整或者启动端口(默认8000)有所调整,需要修改启动和关闭文件
11.其他机子能访问到(配置的ip:8000)就成功了。

老用户部署会涉及到数据库迁移的问题,建议百度学习,将老项目requestnew\request\migrations除了init.py都删除先数据库迁移,然后将这个新生成的0001_initial.py文件放到新工程下的同目录下的地方在对新工程做数据库迁移。

github代码暂时停更,遇到了上传不了代码的问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章