当前位置: 首页 > 工具软件 > Fast Assert > 使用案例 >

fastapi+tortoise单元测试

祖波光
2023-12-01

概述

之前写过一次单元测试的文章,这次主要是完成一部分新的更简洁明了的测试。整个测试现在非常方便

示例

基础测试类

首先我们要有一个基础的测试类,例如:

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
 类似资料: