前言
这是一个使用HttpRunner开发接口平台的简单Demo。
新建Django项目
安装依赖包
pip install httprunner=1.5.6 -i https://pypi.doubanio.com/simple/
模型规划
- 项目Project:包含 名称、创建时间、修改时间
- 测试套件TestSuite:对应HttpRunner的一个yaml文件,包含所属项目、name、base_url、request请求配置、variables用户自定义变量、创建时间、修改时间
- 测试用例TestCase:对应HttpRunner中的一个test段,包含所属TestSuite、name、skip、request、validate、extract、创建时间、修改时间
- 测试结果TestResult:测试套件运行的一次结果信息,包含所属TestSuite、HttpRunner运行summary中的时间信息、统计信息、平台信息、详情等
自定义YamlField
由于TestSuite中的request、variables以及用例中的request我们需要使用Python的字典格式,用例中的validate和extract需要使用Python的列表格式。而Django中这些只能按字符串格式TextField存储。
我们编写一个自定义YamlField,存库时按字符串存,读取时转为Python字典或列表。
在apitest目录下新建fields.py,内容如下。
串存,读取时转为Python字典或列表。
在apitest目录下新建fields.py,内容如下。
import yaml from django.db import models class YamlField(models.TextField): def to_python(self, value): # 将数据库内容转为python对象时调用 if not value: value = {} if isinstance(value, (list, dict)): return value return yaml.safe_load(value) def get_prep_value(self, value): # create时插入数据, 转为字符串存储 return value if value is None else yaml.dump(value, default_flow_style=False) def from_db_value(self, value, expression, connection): # 从数据库读取字段是调用 return self.to_python(value)
使用抽象模型
由于好几个项目、测试套件、测试用例都需要名称、创建时间、修改时间三个属性。为了简化代码,这里创建一个抽象模型ModelWithName,抽象模型用来通过继承来复用属性,并不会创建表。
修改apitest/models.py,添加:
from django.db import models class ModelWithName(models.Model): class Meta: abstract = True name = models.CharField("名称", max_length=200) created = models.DateTimeField('创建时间', auto_now_add=True) modified = models.DateTimeField('最后修改时间', auto_now=True) def __str__(self): return self.name
编写模型
修改apitest/models.py,添加:
class Project(ModelWithName): class Meta: verbose_name_plural = verbose_name = '项目' class TestSuite(ModelWithName): """对应httprunner的一个yaml文件""" class Meta: verbose_name_plural = verbose_name = '测试套件' project = models.ForeignKey(Project, verbose_name='项目', related_name='suites', on_delete=models.CASCADE) base_url = models.CharField('域名', max_length=500, blank=True, null=True) # 对应config/base_url request = YamlField('请求默认配置', blank=True) # 对应config/request variables = YamlField('变量', blank=True) class TestCase(ModelWithName): """对应httprunner中的一个test""" class Meta: verbose_name_plural = verbose_name = '测试用例' suite = models.ForeignKey(TestSuite, verbose_name='测试套件', related_name='tests', on_delete=models.CASCADE) skip = models.BooleanField('跳过', default=False) request = YamlField('请求数据') # 对应config/request extract = YamlField('提取请求', blank=True) validate = YamlField('断言', blank=True) cla<strong style="color:transparent">本文来源gao@daima#com搞(%代@#码@网&</strong>ss TestResult(models.Model): class Meta: verbose_name_plural = verbose_name = '测试结果' suite = models.ForeignKey(TestSuite, verbose_name='测试套件', related_name='results', on_delete=models.CASCADE) success = models.BooleanField('成功') start_at = models.DateTimeField('开始时间') duration = models.DurationField('持续时间') platform = models.TextField('平台信息') test_run = models.SmallIntegerField('运行') successes = models.SmallIntegerField('成功') skipped = models.SmallIntegerField('跳过') failures = models.SmallIntegerField('失败') errors = models.SmallIntegerField('出错') expected_failures = models.SmallIntegerField('预期失败') unexpected_successes = models.SmallIntegerField('非预期成功') details = models.TextField('详情') created = models.DateTimeField('创建时间', auto_now_add=True) def __str__(self): return self.suite.name + '-测试结果'