概述
之前写过一次单元测试的文章,这次主要是完成一部分新的更简洁明了的测试。整个测试现在非常方便
示例
基础测试类
首先我们要有一个基础的测试类,例如:
import random
from fast_tmp.models import User
from httpx import AsyncClient, Response
from tortoise.contrib.test import TestCase
from xx.app import app
class BaseTest(TestCase):
"""
基础测试类
"""
connection_name = "models"#注意,TestCase里面测试的时候是没办法自定义测试链接名称的,需要修改内部代码,修改方式会在后面放出来。
# 创建一些公共方法
async def create_student(
self,
):
user = User(
username="".join(
random.sample(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 5
)
)
)
user.set_password("mininet")
await user.save()
return user
# 每个测试启动的时候执行的代码
async def setUp(self) -> None:
"""
创建用户
"""
user = User(username="admin")
user.set_password("mininet")
user.is_superuser = True
await user.save()
# 获取异步的访问接口的客户端
def get_client(self, headers=None):
return AsyncClient(app=app, base_url="http://test", headers=headers)
async def get_headers(self):
token = await self.get_token()
return {"Authorization": f"Bearer {token}"}
async def get_token(self):
client = self.get_client()
async with client:
res: Response = await client.post(
"/api/token-auth",
data={
"grant_type": "",
"username": "admin",
"password": "mininet",
"scope": "",
"client_id": "",
"client_secret": "",
},
)
assert res.status_code == 200
return res.json()["access_token"]
测试代码
有了基础测试类,我们只需要继承他,然后写上自己的测试代码就可以了。
例如
"""
测试教学管理里面的班级管理
"""
from tests.base import BaseTest
class TestClass(BaseTest):
async def test_class_crud(self):
"""
测试班级本身的crud
"""
# 也可以直接调用tortoise-orm的model进行创建或删除
headers = await self.get_headers()
client = self.get_client(headers)
async with client:
# 测试创建班级
classes_list = await client.get(
"/api/v1/classes",
)
assert classes_list.status_code == 200
assert classes_list.json()["total"] == 0
class1 = {"name": "测试班级1", "class_id": "c1"}
assert (
await client.post("/api/v1/classes", json=class1)
).status_code == 200
res = (
await client.get(
"/api/v1/classes",
)
).json()
assert res["total"] == 1
class_pk = res["data"][0]["id"]
# 获取所有学生
student_1 = await self.create_student() # 创建一个学生
all_students = await client.get("/api/v1/classes/students")
assert len(all_students.json()) == 1
# 测试给班级增加或删除学生
students = await client.get(f"/api/v1/classes/{class_pk}/students")
assert students.status_code == 200
assert len(students.json()) == 0
write_student = {
"add_user_ids": [student_1.pk],
"reduce_user_ids": [],
}
assert (
await client.post(
f"/api/v1/classes/{class_pk}/students",
json=write_student,
)
).status_code == 200
students = await client.get(f"/api/v1/classes/{class_pk}/students")
assert students.status_code == 200
assert len(students.json()) == 1
write_student2 = {
"add_user_ids": [],
"reduce_user_ids": [student_1.pk],
}
assert (
await client.post(
f"/api/v1/classes/{class_pk}/students",
json=write_student2,
)
).status_code == 200
students = await client.get(f"/api/v1/classes/{class_pk}/students")
assert students.status_code == 200
assert len(students.json()) == 0
# 测试增加或删除课程
class_courses = await client.get(
f"/api/v1/classes/{class_pk}/courses"
)
assert class_courses.status_code == 200
assert len(class_courses.json()["courses"]) == 0
编写conftest.py
这个文件必须在根目录,必不可少,主要作用是创建一个测试数据库,在测试结束之后删除数据库。
你们对着抄就行了:
import os
import pytest
from tortoise.contrib.test import finalizer, initializer
@pytest.fixture(scope="session", autouse=True)
def initialize_tests(request):
db_url = os.environ.get("TORTOISE_TEST_DB", "sqlite://:memory:")# 这里配置的内存数据库,有些情况下mysql等数据库和sqlite可能不兼容
initializer(["tests.testmodels"], db_url=db_url, app_label="models")# 这里的model直接配置tortoise_orm里面的models列表就行了,app_label是app的名称
request.addfinalizer(finalizer)
修改tortoise-orm代码里面的bug
修改TestCase类里面的函数:
class TestCase(TruncationTestCase):
...
connection_name: str = "moddels"# 增加这么个环境变量
async def _run_outcome(self, outcome, expecting_failure, testMethod) -> None:
_restore_default()
self.__db__ = Tortoise.get_connection(self.connection_name)
...
执行测试
执行测试的方式如下:
在虚拟环境下,执行
coverage run -m pytest
获取代码覆盖率
coverage report
coverage html