新手区 HTTPRunner 实现多环境配置的两种方式

小丸子 · 2018年03月21日 · 最后由 我去催饭 回复于 2020年09月14日 · 2873 次阅读

HttpRunner 实现多环境运行脚本
背景:
目前 httprunner 在测试环境中运行基本没有问题了,但是后续可能要部署到预研环境,生产环境等,需要框架支持多环境,
条件:
1、目前公司有两个环境,测试环境和生产环境
2、两套环境不同的地方:
     1)数据库地址
     2)url 请求的基地址
3)正式服数据的安全性
(一)思路:测试环境和生产环境存在不同的地方就是数据库、地址、用户名及密码(问过开发,数据库表和字段都是一样的)和请求 url 基地址,因此采用单独设置.env 配置文件来配置这些变量,然后通过 pipenv 加载.env 的方式来提取变量使用,并通过命令行参数来灵活配置选取哪一套环境的变量。
步骤:
1、安装配置 pipenv 命令行:pip install pipenv
2、HttpRunner 还借鉴了 pipenv 加载.env 的方式
在项目中,创建.env 文件【正式服、测试服独立】,将敏感数据信息放置到其中,存储采用 name=value 的格式:
UserName=admin
Password=123456
PROJECT_KEY=ABCDEFGH
(同时,.env 文件不应该添加到代码仓库中,建议将.env 加入到.gitignore 中)。
默认情况下,.env 文件应该位于运行 hrun 命令的同级目录下,在此情况下,运行 hrun 命令时就会自动将.env 文件中的内容加载到运行时的环境变量中。
3、使用敏感数据¶
在 debugtalk.py 文件中,通过 os.environ 获取指定的环境变量数据。
import os
UserName = os.environ["UserName"] # adminPassword = os.environ["Password"] # 123456PROJECT_KEY = os.environ["PROJECT_KEY"]) # ABCDEFGH
然后,在 YAML/JSON 格式的测试用例中,就可以通过 $var 的方式获取到敏感数据了。

  • test: name: login request: url: http://host/api/login method: POST headers: Content-Type: application/json json: username: $UserName password: $Password validate: - eq: [status_code, 200] 4、Jenkins 分别配置正式服、测试服命令行,单独运行 .env 文件位于其它位置,或者采用了不同的文件名称,通过--dot-env-path 参数指定文件路径,控制正式服、测试服数据存放: $ hrun /path/to/testset.yml --dot-env-path /path/to/.env --log-level debug INFO Loading environment variables from /path/to/.env DEBUG Loaded variable: UserName DEBUG Loaded variable: Password DEBUG Loaded variable: PROJECT_KEY (二) 思路:测试环境和生产环境存在不同的地方就是数据库、地址、用户名及密码(问过开发,数据库表和字段都是一样的)和请求 url 基地址,因此采用单独设置 config.ini 配置文件来配置这些变量,然后通过 python 的 ConfigParser 模块来提取变量使用 步骤: 1、新建 config.ini 文件,config.ini 文件格式及使用方法可参考链接:http://blog.csdn.net/miner_k/article/details/77857292 2、新建 base_url.py 用于存放配置的请求 url 的 host # coding=utf8

import ConfigParser
import os
import platform

if 'Windows' == platform.system():
    config_file = os.getcwd()+"\tests\test_env\script\config.ini"
else:
    config_file = os.getcwd()+"/tests/test_env/script/config.ini"

config = ConfigParser.ConfigParser()
config.read(config_file)

3、数据库连接相关变量修改为:
if 'Windows' == platform.system():
    config_file = os.getcwd()+"\tests\test_env\script\config.ini"
else:
    config_file = os.getcwd()+"/tests/test_env/script/config.ini"

config = ConfigParser.ConfigParser()
config.read(config_file)

4、然后将工程中用到的以上变量全部替换,运行工程
问题①:出现错误提示 “ConfigParser instance has no attribute strip”
出问题代码位置

调试后发现这句代码是为了删除字符串类型上下文的空格的,因此在上面仿照作者之前的处理加上一条如果是 ConfigParser 实例就返回上下文
问题②:出现错误提示 “TypeError: an integer is required”
出问题代码位置

该问题是类型不匹配,从问题出现的地方看应该是跟数据库相关,取数据库配置文件时用的都是 get 方法,该方法取出来的都是字符串形式的,所以端口号也变成字符串了,因此取端口号的方法改成 getint()
问题③:出现错误提示 “TypeError: cannot deepcopy this pattern object”
具体失败 log 如下:
Traceback (most recent call last):
  File "E:\codework\SsjApiTest\ate\task.py", line 17, in runTest
    self.assertTrue(self.test_runner._run_test(self.testcase))
  File "E:\codework\SsjApiTest\ate\runner.py", line 97, in _run_test
    parsed_request = self.init_config(testcase, level="testcase")
  File "E:\codework\SsjApiTest\ate\runner.py", line 60, in init_config
    self.context.init_context(level)
  File "E:\codework\SsjApiTest\ate\context.py", line 34, in init_context
    self.testcase_variables_mapping = copy.deepcopy(self.testset_shared_variables_mapping)
  File "D:\Python27\lib\copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "D:\Python27\lib\copy.py", line 328, in _reconstruct
    args = deepcopy(args, memo)
  File "D:\Python27\lib\copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "D:\Python27\lib\copy.py", line 237, in _deepcopy_tuple
    y.append(deepcopy(a, memo))
  File "D:\Python27\lib\copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "D:\Python27\lib\copy.py", line 230, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "D:\Python27\lib\copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "D:\Python27\lib\copy.py", line 230, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "D:\Python27\lib\copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "D:\Python27\lib\copy.py", line 298, in _deepcopy_inst
    state = deepcopy(state, memo)
  File "D:\Python27\lib\copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "D:\Python27\lib\copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "D:\Python27\lib\copy.py", line 174, in deepcopy
    y = copier(memo)
TypeError: cannot deepcopy this pattern object
这个问题比较棘手,出问题的地方是 deepcopy,首先学习了下 deepcopy,深复制和浅复制的最大区别在于所复制的对象,如果是简单的对象,想一个整数,一个字符串,深复制和浅复制效果都一样,但是对于复杂对象如嵌套的列表,list=[1,2,[3,4]],浅复制只会复制列表的第一层数据,而深复制会将列表迭代复制,不管里面嵌套多少层列表,里面嵌套的所有列表也都会被复制,所以如果源数据被修改了,如果只修改第一层数据,那么对深浅复制都没有影响,但是如果修改了源列表中嵌套列表中的数据,那么浅复制后的对象也跟着修改了,而深复制后的对象就不会被修改,这就是 python 中深浅复制方法,各有千秋吧,其实从名字也能猜出它的用法,深浅嘛。具体更详细的讲解可以参考下面的博客链接:
http://blog.csdn.net/qq_32907349/article/details/52190796
知道深复制的意思后,然后去调试代码出问题的第一个 deepcopy,“self.testcase_variables_mapping = copy.deepcopy(self.testset_shared_variables_mapping)”,也就是说深复制 “self.testset_shared_variables_mapping” 的时候无法复制了,该变量的对象类型是 OrderedDict,在附近设置断点 debug 反复调试,最终发现是 “self.testset_shared_variables_mapping” 字典中多了两项,而且在 level 是 testcase 时就无法复制了,因为 config_file 是一个字符串应该不会导致复制不了,而 config 是一个 ConfigParser 对象,猜测应该是 config 导致无法复制,从图中看以后要用到的变量已经提取出来了,所以可以考虑将 config 删除。

因此在复制之前加上如下代码:
if level == "testcase":
    if 'config' in self.testset_shared_variables_mapping.keys(): # 删除一次之后,在删除会提示错误,所以加个判断
        del self.testset_shared_variables_mapping['config']
运行之后没问题
使用方法:
使用时只需修改 config.ini 文件中的 [parameter] 和 [parameter1] 即可,要运行哪套环境,就将哪一套环境修改为 [parameter],不使用的环境就修改为 [parameter1]、[parameter2].......

共收到 3 条回复 时间 点赞

建议中间那段格式乱的地方修改一下,看的眼睛花了、、、

中间那段格式乱的地方可否优化一下呢?本来思路很流畅看下来,遇到中间那段 有点断档

httprunner3 好像不支持--dot-env-path 这个参数了,不知道有什么方式代替?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册