本质上是继承UnitTest实现,可轻松实现
- 数据隔离
- 执行前自动创建测试数据库,默认为test_xxx,可通过'TEST':{'name':'自定义'}
- 执行时settings.debug恒等于false
- 执行后自动销毁测试数据库
- 异常中断时不会删除,下次执行前需要手动确认
- 自动确认
- python3 manage.py test --noinput
- 自动发现
- test_*开头的模块
- UT的子类
- 无序!!
- API test
- 只需要写路由,不启动服务便可直接测view
- 依赖服务需要能联通,比如db, redis等
- 本地容器可加入桥接网络
结合UT,融入CI
- 注册gitlab runner
- shell形式
- 安装python
- 不要通过apt install python
- 安装空间将近1G,却没有pip
- 推荐源码安装
- 不要通过apt install python
- 安装python
- 记得对应路径下,存放测试需要的资源
- shell形式
- 编写yml
-
lint-job: tags: - test stage: build script: - echo "Hello, $GITLAB_USER_LOGIN!" - pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple - pip3 install -r requirements.txt - export PATH=/home/gitlab-runner/.local/bin:$PATH - cd {django project目录}/ - echo "start lint---$PATH" - pylint {django project目录}/ --fail-under=9 - echo "end lint---" test-job: tags: - test stage: test script: - echo "This job tests something:$DEMO_VALUE" - cd {django project目录} - echo "start test---" - python3 manage.py makemigrations && python3 manage.py migrate && python3 manage.py test --noinput - echo "end test---"
-
3. 编写UT
'''
继承TestCase 就创建了一个测试样例。下述二个独立的测试是二个类的方法,
这些方法的命名都以 test 开头。 这个命名约定告诉测试运行者类的哪些方法表示测试。
每个测试的关键是:调用 assertEqual() 来检查预期的输出; 调用 assertTrue() 或 assertFalse() 来验证一个条件;
调用 assertRaises() 来验证抛出了一个特定的异常。使用这些方法而不是 assert 语句是为了让测试运行者能聚合所有的测试结果并产生结果报告。
通过 setUp() 和 tearDown() 方法,可以设置测试开始前与完成后需要执行的指令。 在 组织你的测试代码 中,对此有更为详细的描述。
'''
from django.test import TestCase, Client
from statusTask.models import UserModel, DetectionTaskModel
from utils.fb_enum import TaskEnum
class DemoTestCase(TestCase):
def login(self):
'''
适配自造轮子的登录逻辑
'''
client = Client()
data = {"username": self.name, "password": self.pwd}
response = client.post('/task_admin/login', data, content_type='application/json')
# self.assertEqual(response.status_code, 200)
# 获取返回值
res = response.json()
print(f'login:{res}')
session_id = res.get('data').get('session_id')
return session_id
def setUp(self):
self.ok_series_id = 'seriesid'
self.SUGGESTION = ''
self.name = 'admin1'
self.pwd = '1'
# 造数据
self.user = UserModel.objects.create_user(username=self.name, password=self.pwd)
DetectionTaskModel.objects.create(id='task_id', series_id=self.ok_series_id, path='path', week=30, name='name', status=TaskEnum.SUCCESS.value)
# 认证
sid = self.login()
self.cli = Client(HTTP_AUTHORIZATION=sid)
def test_ok(self):
url = '/information'
# res = requests.get(url, timeout=2) # 请勿使用,不然UT中临时创建的DB会无效
res = self.cli.get(url)
print(res.json())
self.assertTrue(res.status_code==200)
def test_404(self):
url = '/not/exit/'
# res = requests.get(url, timeout=2) # 请勿使用,不然UT中临时创建的DB会无效
res = self.cli.get(url,timeout=0.5)
print('>>>>>>>>>>>', res)
self.assertTrue(res.status_code==404)
def test_query_one_ok_report(self):
'''
查询已完成的任务
若需要成功,需要把报告数据拷贝到runner容器的对应路径下
'''
url = '/task_admin/test_report'
# res = requests.get(url, timeout=2) # 请勿使用,不然UT中临时创建的DB会无效
res = self.cli.get(url, {'task_status':TaskEnum.SUCCESS.value,'page':1,'psize':1})
print(res.json())
self.assertTrue(res.status_code==200)
res = res.json()
self.assertTrue(len(res['data']['list'])==1)
self.ok_series_id = res['data']['list'][0]['series_id']
print(f'{self.__class__.__name__}--sid---{self.ok_series_id}')
def test_post_suggest(self):
'''
修改建议
'''
url='/suggestion'
self.SUGGESTION = 'haha'
print(f'{self.__class__.__name__}--sid---{self.ok_series_id}')
res = self.cli.post(url,{'series_id': self.ok_series_id,'suggestion': self.SUGGESTION}, content_type='application/json')
print(res.json())
self.assertTrue(res.status_code==200)
def test_get_suggest(self):
'''
获取建议
'''
url='result'
res = self.cli.get(url,{'series_id': self.ok_series_id})
print(f'{self.__class__.__name__}--sid---{self.ok_series_id}')
print('test_get_suggest', res.json())
self.assertTrue(res.status_code==200)
res = res.json()
self.assertTrue(res['data']['doctor']['suggestion']==self.SUGGESTION)
有以下几点需要特别注意
-
请求一定要使用from django.test import Client,否则测试数据会污染正式的数据库
-
Client设置hearder传参,比如像设置header的Authorization
-
必须传HTTP_AUTHORIZATION=xxx
-
-
case中的test_*方法执行是无序的