python requests pytest allure 接口自动化项目

第三方模块

allure-pytest

pymysql

requests

main.py

import os

import pytest


if __name__ == '__main__':
    pytest.main(["--alluredir","./alluretmp"])
    os.system("allure generate ./alluretmp -o ./allure-report --clean")

config.py

import os

import pytest
import requests

from common.encryOPS import EncryOPS
from common.getBaseInfo import GetBaseInfo
from common.pathSetting import PathSetting


@pytest.fixture(scope="session",autouse=True)
def get_token():
    config_path = PathSetting().path_setting("test_config_path")
    url = GetBaseInfo().get_value_bySection(config_path+"\\baseEnv.ini","testenv")["baseurl"] + "user/login"
    username = GetBaseInfo().get_value_byoption(config_path+"\\baseEnv.ini","userinfo","username")
    pwd = GetBaseInfo().get_value_byoption(config_path+"\\baseEnv.ini", "userinfo", "pwd")

    pwd = EncryOPS().encry_sha1(pwd.encode("utf-8"))
    data ={
        "username": username,
        "password": pwd
    }
    try:
        res = requests.post(url=url, params=data)
        token = res.json()["data"]["token"]
        os.environ["token1"] = str(token)
    except Exception as e:
        print(f"初始化登录失败conftest.get_token,用户名{username},密码{pwd},token{token}")


@pytest.fixture(scope="session",autouse=True)
def clean_tmpallure():
    project_path = PathSetting().path_setting("project_path")
    tmp_allure_path = project_path+"\\alluretmp"
    tmpallure_files =os.listdir(tmp_allure_path)
    for fl in tmpallure_files:
        fl_path = tmp_allure_path+"\\"+fl
        if fl.endswith(".json") or fl.endswith(".txt"):
            os.remove(fl_path)


def get_my_sql_info():
    test_config_path = PathSetting().path_setting("test_config_path")+"\\baseEnv.ini"
    mysql_info = GetBaseInfo().get_value_bySection(test_config_path, "mysql")
    mysql_info["port"] = int(mysql_info["port"])
    return mysql_info

pytest.ini

[pytest]

addopts = -vs
testpaths = ./testcase
python_files = test*.py
python_classes =Test*
python_functions = test_*
markers = smoke
    story: sdv
    sit: sit
    uat: uat

common/dbconn.py

import pymysql as pymysql

from common.getBaseInfo import GetBaseInfo
from common.logger import logger
from common.pathSetting import PathSetting


class Dbconn(object):
    def __init__(self,dbinfo):
        self.db = pymysql.connect(cursorclass=pymysql.cursors.DictCursor    ,**dbinfo)
        self.cursor = self.db.cursor()
    def select(self,sql):
        try:
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
            return result
        except Exception as e:
            print(e)
            logger.error("执行SELECT SQL失败",e)
    def execute(self,sql):
        self.cursor.execute(sql)
        self.db.commit()
    def close(self):
        self.cursor.close()
        self.db.close()

common/encryOPS.py

import hashlib

class EncryOPS:
    @staticmethod
    def encry_sha1(value):
        return hashlib.sha256(value).hexdigest()


common/getbaseinfo.py
import configparser as configparser


class GetBaseInfo:

    def __init__(self):
        self.config = configparser.ConfigParser()

    def get_all_sections(self,path):
        self.config.read(path)
        return self.config.sections()

    def get_all_options(self,path,section):
        self.config.read(path)
        return self.config.options(section)

    def get_value_byoption(self,path,section,option):
        try:
            self.config.read(path)
            return self.config.get(section,option)
        except configparser.NoSectionError as e:
            print("error is",e)
            return 'the section"{}"->options"{}" is no value'.format(section,option)

    def get_value_bySection(self,path,section):
        try:
            self.config.read(path)
            options = self.config.options(section)
            sect_list ={}
            for opt in options:
                opt_value = self.config.get(section,opt)
                sect_list[opt] = opt_value
            return(sect_list)
        except Exception as e:
            print("error is",e)
            return(f"no section{section} in the path{path}")

        common/getheaders.py

class GetHeaders:
    @staticmethod
    def get_header(token):
        try:
            headers = {
                "Content-Type": "application/json",
                "token": token
            }
            return headers
        except Exception as e:
            print("get_header is error:",e)

    @staticmethod
    def get_header_token(token):
        try:
            headers = {
                "token":token
            }
            return headers
        except Exception as e:
            print("get_header_token is error:", e)

common/getyml.py

import codecs

import yaml


class GetYmlData:
    @staticmethod
    def get_yml_data(filepath):
        try:
            with open(filepath,'r',encoding='utf-8') as f:
                datas = yaml.load(stream=f,Loader=yaml.FullLoader)
                return datas
        except Exception as e:
            print("获取yml文件内容失败:get_yml_data",e)

    @staticmethod
    def get_yml_data_byc(filepath):
        try:
            with codecs.open(filepath,'r',encoding='utf-8',errors='ignores') as f:
                datas = yaml.load(stream=f, Loader=yaml.FullLoader)
                return datas
        except Exception as e:
            print("获取yml文件内容失败:get_yml_data_byc", e)

common/pathsetting.py

import os.path


class PathSetting:
    def path_setting(self,path_type):
        project_path = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
        if path_type == "test_cases_path":
            testcases_path = project_path+"\\testcase"
            return testcases_path
        elif path_type == "test_datas_path":
            testdatas_path = project_path+"\\testdatas"
            return testdatas_path
        elif path_type == "test_config_path":
            return project_path +"\\config"
        elif path_type == "project_path":
            return project_path

common/readupdate_dcm.py

# -*- coding:utf-8 -*-
import os
import shutil
import pydicom as pd
import SimpleITK as ITK


class ReadUpdateDicom:
    @staticmethod
    def read_dicom(file_path):
        dicom_files = os.listdir(file_path)
        studyInstanceUid_lst = []
        seriesInstanceUid_lst = []
        position_lst = []
        position_dct = {}
        instanceNumber_lst = []
        bodyPart_lst = []
        sopInstanceUid_lst = []
        for fl in dicom_files:
            if fl.endswith(".dcm"):
                dicom_data = pd.read_file(dicom_path + "\\" + fl)
                dicom_imagePositionPatient = 0
                try:
                    dicom_imagePositionPatient = dicom_data.get("ImagePositionPatient")[-1]
                except:
                    pass
                dicom_instanceNumber = dicom_data.get("InstanceNumber")
                dicom_studyInstanceUid = dicom_data.get("StudyInstanceUID")
                dicom_SeriesInstanceUID = dicom_data.get("SeriesInstanceUID")
                dicom_BodyPartExamined = dicom_data.get("BodyPartExamined")
                dicom_SOPInstanceUID = dicom_data.get("SOPInstanceUID")
                if dicom_imagePositionPatient != 0:
                    if dicom_imagePositionPatient not in position_lst:
                        position_lst.append(dicom_imagePositionPatient)
                        position_dct[dicom_imagePositionPatient] = 1
                    else:
                        position_dct[dicom_imagePositionPatient] += 1
                if dicom_studyInstanceUid not in studyInstanceUid_lst:
                    studyInstanceUid_lst.append(dicom_studyInstanceUid)
                if dicom_SeriesInstanceUID not in seriesInstanceUid_lst:
                    seriesInstanceUid_lst.append(dicom_SeriesInstanceUID)
                if dicom_BodyPartExamined not in bodyPart_lst:
                    bodyPart_lst.append(dicom_BodyPartExamined)
                instanceNumber_lst.append(dicom_instanceNumber)
                sopInstanceUid_lst.append(dicom_SOPInstanceUID.split(".")[-1])

        # 多个study或者series不支持
        if len(studyInstanceUid_lst) > 1 or len(seriesInstanceUid_lst) > 1:
            print('\033[31m多个study或者series不支持\033[0m')
            exit(0)
        # 判断当前影像是否为HEAD头部影像
        print("\33[32;40m规则1:BodyPartExamined 是否为HEAD头部影像:\33[0m")
        if len(bodyPart_lst) == 1 and bodyPart_lst[0] == "HEAD":
            print('当前影像的扫描部位均为HEAD')
        else:
            print('\33[31m当前影像的扫描部位不是全部为HEAD:\\33[0m')
            for i in bodyPart_lst:
                print(i, end=" ")
        # 统计总计有多少个扫描时相
        print("\33[32;40m规则2:扫描部位统计及扫描部位是否等差数列:\33[0m")
        print('扫描部位总计:{}'.format(len(position_lst)))
        if len(position_lst) >= 1:
            position_lst = list(map(int, position_lst))
            position_lst.sort()
            print('扫描部位列表:{}'.format(position_lst))
            is_sequence = True
            for i in range(2, len(position_lst)):
                value = round(position_lst[1] - position_lst[0], 2)
                if round(position_lst[i] - position_lst[i - 1], 2) != value:
                    is_sequence = False
                    print("当前扫描部位与前一张影像扫描部位不成等差数列:", position_lst[i])
                    break
            if is_sequence:
                print("影像扫描部位成等差数列,差值为:{}".format(round(position_lst[1] - position_lst[0], 2)))
            # 统计每个扫描时相下的扫描次数
            print("\33[32;40m规则3:统计每个扫描时相下的扫描次数:\33[0m")
            n = 0
            for i in position_dct:
                print('Z轴为{}:'.format(i), end=" ")
                print('{}次'.format(position_dct[i]), end="    ")
                n += 1
                if n % 10 == 0:
                    print()
            print()
        # 统计InstanceNumber是否从1,按步长为1递增
        print("\33[32;40m规则4:统计InstanceNumber是否从1,按步长为1递增:\33[0m")
        instanceNumber_lst = list(map(int, instanceNumber_lst))
        instanceNumber_lst.sort()
        if instanceNumber_lst[0] != 1:
            print('\033[31m影像InstanceNumber最小值不是1,实际值为{},文件名为{}\033[0m'.format(instanceNumber_lst[0], dicom_files[0]))
        flag = True
        for i in range(1, len(instanceNumber_lst)):
            if instanceNumber_lst[i] - instanceNumber_lst[i - 1] != 1:
                print('\033[31m当前影像与上一张影像步长不为1,实际为{},文件名为{}\033[0m'.format(
                    instanceNumber_lst[i] - instanceNumber_lst[i - 1], dicom_files[i]))
                flag = False
                break
        if flag:
            print("规则4验证OK:当前影像步长均为1.")
        print("instanceNumber_lst", instanceNumber_lst)

        print("\33[32;40m规则5:SOPInstanceUID是否连续且步长为1:\33[0m")
        flag = True
        sopInstanceUid_lst = list(map(int, sopInstanceUid_lst))
        sopInstanceUid_lst_new = sorted(sopInstanceUid_lst)
        for i in range(1, len(sopInstanceUid_lst_new)):
            if int(sopInstanceUid_lst_new[i]) - int(sopInstanceUid_lst_new[i - 1]) != 1:
                flag = False
                print('\33[31m当前影像SOPInstanceUID不连续,实际步长为{},当前影像SOPInstanceUID为{}\33[0m'.format(
                    int(sopInstanceUid_lst_new[i]) - int(sopInstanceUid_lst_new[i - 1]), sopInstanceUid_lst_new[i]))
                break
        if flag:
            print("规则5验证OK:当前影像SOPInstanceUID连续且步长为1:")
            print(sopInstanceUid_lst_new)

    @staticmethod
    def update_dicom(filepath, params, patientname, patientid):
        dicom_files = os.listdir(filepath)
        for fl in dicom_files:
            fl_path = os.path.join(dicom_path, fl)
            try:
                dicom_data = pd.read_file(dicom_path + "\\" + fl)
                # 每次执行需要修改
                update_data = params
                # 修改患者属性
                dicom_data.PatientName = patientname
                dicom_data.PatientID = patientid
                # dicom_data.PatientSex ="F"
                # dicom_data.PatientAge ="022Y"
                # dicom_data.PatientBirthDate = "19780120"
                # 修改影像属性 测试上传规则
                # dicom_data.BodyPartExamined = "BODY"
                # dicom_data.Modality = "XA"
                dicom_data.SliceThickness = 0.5
                # dicom_data.Rows = 555
                # dicom_data.Columns = 555
                # 修改 study数据,StudyInstanceUID截取倒数第8到倒数第14位
                dicom_data.StudyID = update_data
                study_instanceuid = dicom_data.get("StudyInstanceUID")
                try:
                    start_studyinstanceuid = study_instanceuid[0:-14]
                    middle_StudyInstanceUID = update_data + str(int(study_instanceuid[-10:-6]) + 1).rjust(4, "0")
                    en_StudyInstanceUID = study_instanceuid[-4:]
                    dicom_data.StudyInstanceUID = start_studyinstanceuid + middle_StudyInstanceUID + en_StudyInstanceUID
                except:
                    print('\033[31m影像原始StudyInstanceUID格式不对:{}\033[0m'.format(study_instanceuid))
                # 修改series数据
                # dicom_data.SeriesNumber =update_data
                series_instanceuid = dicom_data.get("SeriesInstanceUID")
                try:
                    start_seriesinstanceuid = series_instanceuid[0:-17]
                    middle_seriesinstanceuid = update_data + str(int(series_instanceuid[-11:-7]) + 1).rjust(4, "0")
                    end_seriesinstanceuid = series_instanceuid[-7:]
                    dicom_data.SeriesInstanceUID = start_seriesinstanceuid + middle_seriesinstanceuid + end_seriesinstanceuid
                    # SOPInstanceUID
                    sopinstanceuid = str(dicom_data.get("SOPInstanceUID")).split(".")
                    before_sopinstanceuid = sopinstanceuid[0:-2]
                    replace_sopinstanceuid = str(int(update_data[-5:]) + 1).ljust(5, "0")
                    after_sopinstanceuid = sopinstanceuid[-1]
                    dicom_data.SOPInstanceUID = ".".join(
                        before_sopinstanceuid) + "." + replace_sopinstanceuid + "." + after_sopinstanceuid
                except:
                    print('\033[31m影像原始SeriesInstanceUID格式不对:{}\033[0m'.format(series_instanceuid))
                dicom_data.save_as(fl_path)
            except:
                continue

    @staticmethod
    def copy_dicom(src_path, dest_path, params):
        src_files = os.listdir(src_path)
        for i, fl in enumerate(src_files):
            if fl.endswith(".dcm"):
                srcfl_path = os.path.join(src_path, fl)
                # desc_flname = params + fl.split(".")[0] + ".dcm"
                desc_flname = '1' + fl.split(".")[0] + ".dcm"
                destfl_path = os.path.join(dest_path, desc_flname)
                shutil.copy(srcfl_path, destfl_path)
        # 修改目标路径下series数据
        """
            SeriesInstanceUID
            SOPInstanceUID
            seriesnumber
        """
        update_data = params
        dest_dicom_files = os.listdir(dest_path)
        for j, fl in enumerate(dest_dicom_files):
            file_path = os.path.join(dest_path, fl)
            dicom_data = pd.read_file(dest_path + "\\" + fl)
            series_instanceuid = dicom_data.get("SeriesInstanceUID")
            sopinstanceuid = str(dicom_data.get("SOPInstanceUID")).split(".")
            dicom_data.SeriesNumber = dicom_data.get("SeriesNumber") + 1
            try:
                # SeriesInstanceUID
                start_seriesinstanceuid = series_instanceuid[0:-17]
                middle_seriesinstanceuid = update_data + str(int(series_instanceuid[-11:-7]) + 1).rjust(4, "0")
                end_seriesinstanceuid = series_instanceuid[-7:]
                dicom_data.SeriesInstanceUID = start_seriesinstanceuid + middle_seriesinstanceuid + end_seriesinstanceuid
                # SOPInstanceUID
                before_sopinstanceuid = sopinstanceuid[0:-2]
                replace_sopinstanceuid = str(int(update_data) + 1).ljust(5, "0")
                after_sopinstanceuid = sopinstanceuid[-1]
                dicom_data.SOPInstanceUID = ".".join(
                    before_sopinstanceuid) + "." + replace_sopinstanceuid + "." + after_sopinstanceuid
            except:
                print('\033[31m影像原始SeriesInstanceUID格式不对:{}\033[0m'.format(series_instanceuid))
            dicom_data.save_as(file_path)

    @staticmethod
    def delete_image_position(path, image_position_lst2):
        dicom_files = os.listdir(path)
        image_position_lst2 = list(map(float, image_position_lst2))
        for file in dicom_files:
            file_path = os.path.join(path, file)
            file_datas = pd.read_file(file_path)
            file_location = file_datas.get("ImagePositionPatient")[-1]
            if file_location in image_position_lst2:
                os.remove(file_path)

    @staticmethod
    def rename_image(dicom_path2):
        files = os.listdir(dicom_path2)
        for file in files:
            if not file.endswith(".dcm"):
                file_path = os.path.join(dicom_path2, file)
                new_file = file + ".dcm"
                new_file_path = os.path.join(dicom_path2, new_file)
                os.renames(file_path, new_file_path)

    @staticmethod
    def get_file_names(dicom_path3):
        files = os.listdir(dicom_path3)
        files = sorted(files)
        for file in files:
            print(file)


if __name__ == '__main__':
    """  
    func_name =1 统计校验当前路径文件夹下的影像完整性
    当前不支持一个文件夹下有多个study或者series影像的数据
        1.BodyPartExamined 是否为HEAD头部影像
        2.扫描部位统计及扫描部位是否等差数列
        3.统计每个部位扫描次数
        4.InstanceNumber是否连续,且最小值为1
        5.SOPInstanceUID是否连续且步长为1
    func_name = 2 直接修改当前路径下的所有dicom文件属性
        每次执行必须修改:
            dicom_path
            update_data
            dicom_data.PatientName
            dicom_data.PatientID
    func_name = 3 直接基于源路径下的dicom文件进行copy,生成一个新的series
        每次执行必须修改param_data,不能每次都基于同一份数据进行copy,否则每次copy后的seriesNumber都相同
    fun_name =4 :删除指定扫描部位的影像ImagePositionPatient
    fun_name = 5 :将指定路径下的文件名拼上.dcm
    fun_name = 6 : 将指定路径下的文件拼成2000个,名读取出来   --- UI自动化构造2000个影像
    """
    # 入口
    func_name = 2
    # 修改参数值
    param_data = "100053"
    # 修改患者属性
    patient_name = "UIAUTO_023"
    patient_id = "100053"

    # dicom文件路径
    dicom_path = "/".join(str(r'E:\autotest\ais_ui_testdatas\upload\upload_less_30pc_study').split("\\"))
    destination_path = "/".join(str(r"E:\项目\手术导航系统\影像数据\林华桂-cta-test-copy-ok").split("\\"))

    try:
        if func_name == 1:
            ReadUpdateDicom().read_dicom(file_path=dicom_path)
            print("\33[32;40m统计完成\33[0m")
        elif func_name == 2:
            ReadUpdateDicom().update_dicom(filepath=dicom_path, params=param_data, patientname=patient_name,
                                           patientid=patient_id)
            print("\33[32;40m更新完成\33[0m")
        elif func_name == 3:
            ReadUpdateDicom().copy_dicom(dicom_path, destination_path, param_data)
            print("\33[32;40m文件拷贝完成\33[0m")
        elif func_name == 4:
            image_position_lst2 = [6]
            ReadUpdateDicom().delete_image_position(dicom_path, image_position_lst2)
            print("\33[32;40m已经删除指定的ImagePositionPatient的影像\33[0m")
        elif func_name == 5:
            ReadUpdateDicom().rename_image(dicom_path)
            print("\33[32;40m非dcm文件已经重新更名.dcm格式\33[0m")
        elif func_name == 6:
            ReadUpdateDicom().get_file_names(dicom_path)
    except:
        print('执行异常')

config/env.ini

[testenv]
baseUrl = http://172.31.1.16:8081/
[userinfo]
username = ais
pwd = 123456
[mysql]
host = 172.31.1.16
port = 3306
user = ais
password =  ais
database = ais

testcase/testCTP/testCTPList.py

import os

import allure
import pytest
import requests

from common.getBaseInfo import GetBaseInfo
from common.getHeaders import GetHeaders
from common.getYmlData import GetYmlData
from common.pathSetting import PathSetting


@allure.feature("CTP诊断List")
class TestCTPList:
    test_datas_path = PathSetting().path_setting("test_datas_path")+"\\testCTP\\testCTPList.yml"
    test_datas = GetYmlData().get_yml_data(test_datas_path)
    test_config_path = PathSetting().path_setting("test_config_path")+"\\baseEnv.ini"
    baseurl = GetBaseInfo().get_value_byoption(test_config_path,'testenv','baseUrl')

    @allure.story("CTP诊断List查询")
    @pytest.mark.parametrize('datas',test_datas)
    def test_ctp_search(self,datas):
        with allure.step("设置token及headers"):
            token = os.environ.get("token1")
            headers = GetHeaders().get_header_token(token)
            method = datas["method"]
        with allure.step("获取测试用例参数"):
            url = TestCTPList.baseurl+datas["url"]
            data1 = datas["data"]
            validate_code = datas["validate"]["code"]
        with allure.step(f"调用查询接口{url}"):
            res = requests.get(url,data=data1, headers=headers)
        with allure.step(f"校验实际接口返回code是否为{validate_code},"):
            assert res.json()["code"] == validate_code

testcase/testlist/teststudylist.py

import os
import allure
import pytest
import requests

from common.getBaseInfo import GetBaseInfo
from common.getHeaders import GetHeaders
from common.getYmlData import GetYmlData
from common.logger import logger
from common.pathSetting import PathSetting


@allure.parent_suite("影像模块")
@allure.feature("影像列表")
class TestStudyList:
    test_datas_path = PathSetting().path_setting("test_datas_path")+"\\testStudyList\\testStudyList.yml"
    test_config_path = PathSetting().path_setting("test_config_path")+"\\baseEnv.ini"

    test_datas = GetYmlData().get_yml_data(test_datas_path)
    baseurl = GetBaseInfo().get_value_bySection(test_config_path,"testenv")["baseurl"]

    @allure.story("列表查询")
    @allure.title("测试测试用例执行列表查询")
    @pytest.mark.parametrize("datas",test_datas)
    def test_study_search(self,datas):
        token = os.environ.get("token1")
        headers1 = GetHeaders().get_header_token(token)
        url = TestStudyList.baseurl+datas["url"]
        data1 = datas["data"]
        validate_code = datas["validate"]["code"]
        validate_total = datas["validate"]["data"]["total"]
        logger.debug("Begin to send request:"+url)
        with allure.step(f"开始发送请求:{url}"):
            res = requests.get(url,params=data1,headers=headers1)
        with allure.step(f"获取接口{url}返回值"):
            res_code = res.json()["code"]
            res_total = res.json()["data"]["total"]
        with allure.step("开始数据校验"):
            logger.debug("Begin to Check The Result:"+str(validate_total))
            assert res_code == validate_code
            assert res_total == validate_total


if __name__ == '__main__':
    TestStudyList().test_study_search()

testcase/testlist/teststudyalign.py


import os
import time

import allure
import pytest
import requests

from common.dbconn import Dbconn
from common.getBaseInfo import GetBaseInfo
from common.getHeaders import GetHeaders
from common.getYmlData import GetYmlData
from common.pathSetting import PathSetting


@allure.feature("影像列表")
class TestStudyRealign:
    test_datas_path = PathSetting().path_setting("test_datas_path")+"\\testStudyList\\testStudyRealign.yml"
    test_datas = GetYmlData().get_yml_data(test_datas_path)
    test_config_path = PathSetting().path_setting("test_config_path")+"\\baseEnv.ini"
    baseurl = GetBaseInfo().get_value_bySection(test_config_path, "testenv")["baseurl"]

    mysql_config_path = PathSetting().path_setting("test_config_path")+"\\mysql.yml"
    mysql_info = GetBaseInfo().get_value_bySection(test_config_path, "mysql")
    mysql_info["port"] = int(mysql_info["port"])

    @allure.story("影像校正")
    @allure.title("根据不同状态发起影像校正")
    @pytest.mark.parametrize("testdata",test_datas)
    def test_study_realign(self,testdata):
        headers = GetHeaders().get_header(os.environ.get("token1"))
        data = testdata["data"]
        patient_name = testdata["data"]["patient_name"]
        url = TestStudyRealign.baseurl + testdata["url"]
        study_status = testdata["data"]["study_status"]
        exp_status = testdata["validate"]["exp_status"]
        with allure.step("定义SQL"):
            """
            select_studyid  : 查询study_id
            update_study_realign_status : 更新study校正状态
            select_study_status    :获取校正后的study状态
            """
            select_studyid_sql = f'select id from t_study ts where exists(\
            select 1 from t_patient tu where ts.patient=tu.id and\
                tu.patient_name = \'{patient_name}\')'
            exec_study_realign_status=f'update  t_study_realign tsr set\
             tsr.request_status ={study_status} where exists(\
                select 1 from t_study ts where tsr.study = ts.id and exists ( select 1 from t_patient  tu where\
                ts.patient = tu.id and tu.patient_name = \'{patient_name}\'))'
            # select_study_status = f'select request_status from t_study_realign tsr where exists(\
            #     select 1 from t_study ts where tsr.study = ts.id and exists ( select 1 from t_patient  tu where\
            #     ts.patient = tu.id and tu.patient_name = \'{patient_name}\'))'
        with allure.step("执行SQL查询study_id"):
            db = Dbconn(TestStudyRealign.mysql_info)
            study_id = db.select(select_studyid_sql)[0]["id"]
        with allure.step(f"更新当前study影像诊断状态{study_status}"):
            db.execute(exec_study_realign_status)
            db.close()
        with allure.step(f"拼接完整URL接口信息{url}/{study_id}"):
            url = url+"/"+str(study_id)
        with allure.step(f"发送校正请求{url}"):
            res = requests.post(url,json=data,headers=headers)
        with allure.step("开始接口校验"):
            assert testdata["validate"]["code"] == res.json()["code"]
            assert testdata["validate"]["message"] == res.json()["message"]
        # with allure.step(f"校验最终的影像状态是否为{exp_status},默认等待5分钟"):
        #     time.sleep(300)
        #     status = db.select(select_study_status)[0]["request_status"]
        #     db.close()
        #     assert status == exp_status


if __name__ == '__main__':
    TestStudyRealign().test_study_realign()

testcase/testlist/teststudyupload.py

from datetime import datetime
import os

import allure
import pytest
import requests

from common.dbconn import Dbconn
from common.getBaseInfo import GetBaseInfo
from common.getHeaders import GetHeaders
from common.getYmlData import GetYmlData
from common.logger import logger
from common.pathSetting import PathSetting


@allure.parent_suite("影像模块")
@allure.feature("影像上传")
class TestStudyUpload:

    test_datas_base_path = PathSetting().path_setting("test_datas_path")
    test_datas_path = test_datas_base_path+"\\testStudyList\\testStudyUpload.yml"
    test_datas = GetYmlData().get_yml_data(test_datas_path)
    for data_ in test_datas:
        data_["data"]["file_path"] = test_datas_base_path+data_["data"]["file_path"]
    test_config_path = PathSetting().path_setting("test_config_path")+"\\baseEnv.ini"
    baseurl = GetBaseInfo().get_value_bySection(test_config_path, "testenv")["baseurl"]

    config_test_path = PathSetting().path_setting("test_config_path") + "\\mysql.yml"
    mysql_info = GetBaseInfo().get_value_bySection(test_config_path, "mysql")
    mysql_info["port"] = int(mysql_info["port"])

    @allure.story("影像上传")
    @allure.title("根据影像状态进行影像上传")
    @pytest.mark.parametrize("testdata",test_datas)
    def test_study_upload_001(self,testdata):
        file_sets = set()
        files_path = testdata["data"]["file_path"]
        filedirs = os.listdir(files_path)
        with allure.step(f"选取待上传的文件{files_path}"):
            for fl in filedirs:
                fl_path = files_path + fl
                file_sets.add((('file',(fl,open(fl_path,'rb')))))
        with allure.step("获取token并设置headers"):
            token = os.getenv("token1")
            headers1 = GetHeaders().get_header_token(token)
        url = TestStudyUpload.baseurl+testdata["url"]
        files = file_sets
        study_status = testdata["data"]["study_status"]
        series_status = testdata["data"]["series_status"]
        patient_name = testdata["data"]["patient_name"]

        db = Dbconn(TestStudyUpload.mysql_info)
        exec_study_sql = f"update t_study_realign tsr2 set tsr2.request_status ={study_status} where EXISTS(\
        select 1 from  t_study tst where  tsr2.study = tst.id and tst.patient in(\
        select id from t_patient tp where tp.patient_name = \"{patient_name}\"))"

        exec_series_sql = f"update t_series_dx dsd set dsd.request_status = {series_status} where\
        EXISTS(select 1 from t_study_dx tsd1  where  dsd.study_dx =tsd1.id and exists( select\
        1 from t_study ts where tsd1.study = ts.id  and exists( select 1 from t_patient tp\
        where ts.patient =tp.id  and tp.patient_name = \'{patient_name}\')))"

        with allure.step(f"根据测试用例中影像状态为{study_status},影像序列状态为{series_status}:更新t_study_realign.request_status={study_status}\
        更新t_series_dx.request_status ={series_status}"):
            db.execute(exec_study_sql)
            try:
                db.execute(exec_series_sql)
            except Exception:
                logger.log("更新DB异常")
            db.close()
        with allure.step("调用上传文件接口"):
            begin_time = datetime.now()
            rs = requests.post(url, files=files,headers=headers1)
            end_time = datetime.now()
            over_time = end_time-begin_time
            print("上传时间花费:",over_time)

        with allure.step("开始结果校验"):
            response_code = testdata["validate"]["code"]
            response_mess = testdata["validate"]["message"]
            print("testdata",testdata)
            assert  response_code == rs.json()["code"]
            assert response_mess in rs.json()["message"]

if __name__ == '__main__':
    TestStudyUpload.test_study_upload_001()

testcase/testCTP/testCTPDX.py

import json
import os

import allure
import pytest
import requests
from common.dbconn import Dbconn
from common.getBaseInfo import GetBaseInfo
from common.getHeaders import GetHeaders
from common.getYmlData import GetYmlData
from common.logger import logger
from common.pathSetting import PathSetting
from conftest import get_my_sql_info


def update_status(patient_name,study_status,series_dx_status):
    """ 当前只考虑1study 1series
              t_study.status   t_series_dx.request_status
       1.未校正       0                NA
       2.已校正       2                NA
       3.校正异常     5                NA
       4.校正中       1                NA
       5.分析中       3                3
       6.已分析       4                4
       7.分析异常      6               5
       """
    update_study_sql = f'update t_study ts set ts.status ={study_status} where exists \
        (select 1 from t_patient tt where tt.id= ts.patient and tt.patient_name =\'{patient_name}\');'
    update_series_sql = f'update t_series_dx tsd set tsd.request_status ={series_dx_status} where\
        EXISTS(select 1 from t_patient tp where tsd.patient = tp.id and tp.patient_name = \'{patient_name}\');'
    db = Dbconn(TestCTPDX.mysql_info)
    db.execute(update_study_sql)
    if series_dx_status != '':
        db.execute(update_series_sql)
    db.close


def get_series_data():
    series_path = PathSetting().path_setting("test_datas_path") + "\\testCTP\\test_series_dx.yml"
    series_data = GetYmlData().get_yml_data(series_path)
    for i, j in enumerate(series_data):
        j["series_number"] = series_data[i]["series_number"]
        j["name"] = series_data[i]["name"]
        j["study_method"] = series_data[i]["study_method"]
        j["study_url"] = series_data[i]["study_url"]
        j["series_method"] = series_data[i]["series_method"]
        j["series_url"] = series_data[i]["series_url"]
        j["patient_name"] = series_data[i]["patient_name"]
        j["data"]["aifLocation"] = series_data[i]["data"]["aifLocation"]
        j["data"]["vofLocation"] = series_data[i]["data"]["vofLocation"]
        j["validate"]["code"] = series_data[i]["validate"]["code"]
        j["validate"]["result"] = series_data[i]["validate"]["result"]
    return series_data


@allure.feature("CTP诊断")
class TestCTPDX:
    headers = GetHeaders().get_header(os.environ.get("token1"))
    config_path = PathSetting().path_setting("test_config_path")+"\\baseEnv.ini"
    baseurl = GetBaseInfo().get_value_byoption(config_path,"testenv","baseurl")
    study_path = PathSetting().path_setting("test_datas_path")+"\\testCTP\\test_series_dx.yml"
    study_data = GetYmlData().get_yml_data(study_path)
    mysql_info = get_my_sql_info()
    study_dx = ""
    series_data = get_series_data()

    @staticmethod
    def get_study_dx(url):
        try:
            res = requests.post(url=url,params="",headers=TestCTPDX.headers1)
            study_dx = res.json()["data"]["studyDx"]
            return study_dx
        except Exception as e:
            logger.error(f"发起study诊断异常{e},API地址={url},token={TestCTPDX.headers1}")

    @allure.story("根据测试用例进行series诊断")
    @pytest.mark.parametrize("series_data",series_data)
    def test_send_series_dx(self,series_data):
        with allure.step(f"获取测试用例参数{series_data}"):
            study_url = TestCTPDX.baseurl+series_data["study_url"]
            series_url = TestCTPDX.baseurl+series_data["series_url"]
            patient_name = series_data["patient_name"]
            series_number = series_data["series_number"]
            case_name = series_data["name"]
            data = series_data["data"]
        with allure.step(f"定义查询当前患者{patient_name}的studyID的SQL"):
            select_study_id = f'select id from t_study ts  where exists(\
                    select 1 from t_patient tp where ts.patient = tp.id and tp.patient_name =\'{patient_name}\');'
            db = Dbconn(TestCTPDX.mysql_info)
            study_id = db.select(select_study_id)[0]["id"]
            db.close()
        with allure.step(f"重置测试用例中的series诊断状态:{case_name}"):
            if "已分析" in case_name:
                study_status = 4
                series_status = 4
            elif "分析异常" in case_name:
                study_status = 6
                series_status = 5
            elif "分析中" in case_name:
                study_status = 3
                series_status = 3
            else:
                series_status = ''
                if "未校正" in case_name:
                    study_status = 0
                elif "校正中" in case_name:
                    study_status = 1
                elif "已校正" in case_name:
                    study_status = 2
                else:
                    study_status = 5
            update_status(patient_name,study_status,series_status)
        with allure.step("STEP1:发起study诊断,并获取study_dx"):
            url = study_url+f"{study_id}"
            TestCTPDX.study_dx = TestCTPDX().get_study_dx(url)
        with allure.step(f"STEP2:根据StudyDX:{TestCTPDX.study_dx},series_number:{series_number}获取SeriesId"):
            db = Dbconn(TestCTPDX.mysql_info)
            select_series_id = f'select id from t_series ts where ts.series_number =\'{series_number}\' and exists(\
                               select 1 from t_study_dx tsd\
                               where ts.study = tsd.study and tsd.id ={TestCTPDX.study_dx})'
            rst1 = db.select(select_series_id)
            db.close()
            series_id = rst1[0]["id"]
        with allure.step(f"STEP3:根据获取的study_dx:{TestCTPDX.study_dx}及seriesId:{series_id}封装入参"):
            series_data["data"]["seriesId"] = series_id
            series_data["data"]["studyDx"] = TestCTPDX.study_dx
        with allure.step("STEP3:发起Series诊断"):
            try:
                res = requests.post(series_url,json=data,headers=TestCTPDX.headers1)
            except Exception as e:
                logger.error(f"接口返回异常{e}")
        with allure.step("校验接口返回值"):
            assert res.json()["result"] == series_data["validate"]["result"]
            assert res.json()["code"] == series_data["validate"]["code"]

if __name__ == '__main__':
    TestCTPDX().test_send_series_dx()

testdatas/testCTP/testCTPlist.yml

-
  name: 根据患者名称查询
  url: studies/page
  method: get
  data:
    current: 1
    pageSize: 20
    patientName: CAO CHENG JIE
    modality: CT
  validate:
    code: 0
    data:
      total: 1
-
  name: 根据患者ID查询
  url: studies/page
  method: get
  data:
    current: 1
    pageSize: 20
    patientId: 3048500
    modality: CT
  validate:
    code: 0
    data:
      total: 1
-
  name: 根据Study_id查询
  url: studies/page
  method: get
  data:
    current: 1
    pageSize: 20
    studyId: 3201641
    modality: CT
  validate:
    code: 0
    data:
      total: 1

testdatas/testCTP/testCTPDX.yml

-
  name: 已校正的影像发起诊断
  study_method: get
  study_url: dx/study/perfusion/
  series_method: post
  series_url: dx/series/perfusion
  patient_name: AUT0D01
  series_number: 10
  data:
    seriesId: 0000,   # 使用的时候需要重写
    studyDx: 000,      #
    aifLocation:
      x: 178.8928743573265
      y: 220.85573987789206
      z: 0
      t: 15
    "vofLocation":
      x: 272.7357005141389
      y: 220.85573987789206
      z: 0
      t: 15
  validate:
    result: true
    code: 0

testdatas/teststudylist/teststudylist.yml

-
  name: 根据患者名称查询
  url: studies/page
  method: get
  data:
    current: 1
    pageSize: 20
    patientName: Patient_360
  validate:
    code: 0
    data:
      total: 1

testdatas/teststudylist/testalign.yml

-
  name: 未校正状态发起校正操作
  url: study/realign
  data:
    patient_name: AUT0D02
    study_status: 0
  validate:
    code: 0
    message: OK.
    exp_status: 2
-
  name: 已校正状态发起校正操作
  url: study/realign
  data:
    patient_name: AUT0D02
    study_status: 2
  validate:
    code: 0
    message: OK.
    exp_status: 2

testdatas/teststuydlist/testupload.yml

-
  name: 未校正状态进行导入
  url: study/upload
  method: post
  data:
    file_path: \testStudyList\uploaddatas\dicom_study_Patient_370\
    patient_name: Patient_370
    study_status: 0
    series_status: 0
  validate:
    code: 0
    message: Uploaded images submit successfully
-
  name: 导入小于25张图片
  url: study/upload
  method: post
  data:
    file_path: \testStudyList\uploaddatas\dicom_study_Patient_370_less25\
    patient_name: Patient_370
    study_status: 0
    series_status: 0
  validate:
    code: 0
    message: Uploaded images submit successfully
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值