예제 #1
0
 def read_excel():
     LogPrint().info("----------------读取配置文件中测试用例文件的路径信息----------------")
     dcc = DealCommonCfg()
     my_list = dcc.read_config('test_case_file')  # 获得配置文件中的信息内容
     my_dic = {}  # 将获得的内容转换为字典类型
     for i in my_list:
         my_dic[i[0]] = i[1]  # python3的写法,下面是python2的写法
     values = list(my_dic.values())
     return values
예제 #2
0
    def read_file_path(txt_type):
        dcc = DealCommonCfg()
        if txt_type == 'random_param':
            LogPrint().info(
                "----------------读取配置文件中随机函数的txt文件路径信息----------------")
        elif txt_type == 'form_data_template':
            LogPrint().info(
                "----------------读取配置文件中以form_data方式请求的函数所需的txt文件路径信息----------------"
            )
        else:
            LogPrint().info(
                "----------------txt的类型错误,读取不到配置文件中的路径信息----------------")

        my_list = dcc.read_config(txt_type)  # 获得配置文件中的信息内容
        my_dic = {}  # 将获得的内容转换为字典类型
        for i in my_list:
            my_dic[i[0]] = i[1]
        return my_dic
예제 #3
0
class MailSend:
    LogPrint().info("----------------读取配置文件中邮箱信息----------------")
    dcc = DealCommonCfg()
    my_list = dcc.read_config('email_qq')  # 获得配置文件中的信息内容
    my_dic = {}  # 将获得的内容转换为字典类型
    for i in my_list:
        my_dic[i[0]] = i[1]  # python3的写法,下面是python2的写法
        # my_dic[i[0].encode('UTF-8')] = i[1].encode('UTF-8')
    smtp_server = my_dic['smtp_server']  # QQ的SMTP服务器地址
    sender_qq_adr = my_dic['sender_qq_adr']  # 发送人的邮箱地址
    password = my_dic['password']  # QQ邮箱的授权码
    receiver_qq_adr = my_dic['receiver_qq_adr']  # 收件人的邮箱地址
    mail_to_copy = my_dic['mail_to_copy']  # 抄送人的邮箱地址

    def overtime_warn(self, mail_title):
        LogPrint().info("----------------接口超时,开始发送邮件----------------")
        mail_content = 'warn,interface request overtime,please look out!!'  # 邮件的正文内容
        mail_title = mail_title  # 邮件标题

        smtp = SMTP_SSL(self.smtp_server)  # SSL登录
        # smtp.set_debuglevel(1)  # 用来调试的,1为开启调试模式,可以在控制台打印出和SMTP服务器交互的所有信息
        smtp.ehlo(self.smtp_server)  # what't mean
        smtp.login(self.sender_qq_adr, self.password)  # 登录SMTP服务器

        # 邮件主题、如何显示发件人、收件人等信息并不是通过SMTP协议发给MTA,而是包含在发给MTA的文本中的
        msg = MIMEText(mail_content, 'plain', 'utf-8')  # 构造MIMEText对象
        msg['Subject'] = Header(mail_title, 'utf-8')
        msg['From'] = self.sender_qq_adr  # 将邮件主题、发件人和收件人添加到MIMEText中
        msg['To'] = self.receiver_qq_adr
        # 邮件正文是一个str,所以需要将MIMEText对象变成str类型,这一个特别注意,是将对象转换成字符串类型的方法
        smtp.sendmail(self.sender_qq_adr, self.receiver_qq_adr,
                      msg.as_string())
        LogPrint().info("----------------超时邮件发送成功----------------")

        smtp.quit()

    # 接口请求测试完成后的通知邮件,发送html格式的邮件
    def send_mail(self, text):
        LogPrint().info("----------------开始发送测试报告----------------")
        subject = '[AutomationTest]接口自动化测试报告通知'  # 邮件标题
        username = '******'  # 用户邮箱的账号

        msg = MIMEText(text, 'html', 'utf-8')
        msg['Subject'] = subject
        msg['From'] = self.sender_qq_adr
        msg['To'] = ';'.join([self.receiver_qq_adr])
        msg['Cc'] = ';'.join([self.mail_to_copy])
        smtp = SMTP_SSL(self.smtp_server)
        smtp.connect(self.smtp_server)
        smtp.login(username, self.password)
        smtp.sendmail(self.sender_qq_adr,
                      [self.receiver_qq_adr] + [self.mail_to_copy],
                      msg.as_string())
        LogPrint().info("----------------测试报告发送成功----------------")
        smtp.quit()
예제 #4
0
class MysqlDeal:
    dcc = DealCommonCfg()
    my_list = dcc.read_config('mysql')  # 获得配置文件中的信息内容
    my_dic = {}  # 将获得的内容转换为字典类型
    for i in my_list:
        my_dic[i[0].encode('UTF-8')] = i[1].encode(
            'UTF-8')  # 这里将获得的数据由unicode类型转换为str类型,然后存入字典中
    host = my_dic['host']
    user = my_dic['user']
    password = my_dic['password']
    port = int(my_dic['port'])
    charset = my_dic['charset']
    db = my_dic['db']

    def conn_db(self):
        LogPrint().info("----------------正在连接mysql服务器----------------")
        conn = pymysql.connect(  # 连接数据库,其实就是建立一个pymysql.connect()的实例对象conn,该对象有commit()、rollback()、cursor()等属性
            host=self.host,
            user=self.user,
            password=self.password,
            port=self.port,
            charset=self.charset,
            db=self.db)
        LogPrint().info("----------------连接服务器成功----------------")
        cur = conn.cursor()  # 通过游标(指针)cursor的方式操作数据库,该代码作用是得到当前指向数据库的指针
        return (conn, cur)

    @staticmethod
    def select_db(cur, sql):  # 查询数据库,查询条件中需要使用传入的参数
        cur.execute(sql)
        result = cur.fetchall()
        if len(result) == 0:
            LogPrint().info("----------------查询结束,数据库无数据----------------")
            return 0
        else:
            return result

    @staticmethod
    def other_operate_db(conn, cur, sql):  # 增、删、改数据库的操作
        cur.execute(sql)
        conn.commit()

    @staticmethod
    def close_db(conn, cur):
        cur.close()
        conn.close()
예제 #5
0
class MongodbDeal:
    dcc = DealCommonCfg()
    my_list = dcc.read_config('mongodb')  # 获得配置文件中的信息内容
    my_dic = {}  # 将获得的内容转换为字典类型
    for i in my_list:
        my_dic[i[0]] = i[1]
        # my_dic[i[0].encode('UTF-8')] = i[1].encode('UTF-8')      # 这里将获得的数据由unicode类型转换为str类型,然后存入字典中
    host = my_dic['host']
    password = my_dic['password']
    port = int(my_dic['port'])
    user = my_dic['user']

    def conn_db(self, db, collection):
        LogPrint().info("----------------正在连接mongo服务器----------------")
        client = MongoClient(self.host, self.port)  # 建立与数据库系统的连接

        db = client[db]  # 连接数据库
        db.authenticate(self.user, self.password)  # 认证用户密码
        collection = db[collection]
        LogPrint().info("----------------连接服务器成功----------------")
        return db, collection

    @staticmethod
    # 这里statement格式的示例如{'id': '20190410','name': 'Jordan','age': 26,'gender': 'male'}
    def operate(handle, statement):
        md = MongodbDeal()
        db, collection = md.conn_db('test_itf_one', 'test_itf_one')

        if handle == 'insert':
            collection.insert_one(
                statement)  # 同时插入多条数据使用insert_many()方法,参数需要以列表形式传递
        elif handle == 'find':
            result = collection.find_one(
                statement)  # 这里find_one()查询得到的是单个结果,find()则返回一个生成器对象
            return result
        elif handle == 'delete':
            collection.remove(statement)  # 另外两个删除方法delete_one()和delete_many()
        elif handle == 'update':
            collection.update(statement)
        else:
            LogPrint().info("----------------操作类型或执行语句错误----------------")

    def close_db(self):
        client = MongoClient(self.host, self.port)  # 建立与数据库系统的连接
        client.close()
예제 #6
0
class RedisDeal:
    dcc = DealCommonCfg()
    my_list = dcc.read_config('redis')  # 获得配置文件中的信息内容
    my_dic = {}  # 将获得的内容转换为字典类型
    for i in my_list:
        my_dic[i[0]] = i[1]  # python3的写法,以下是python2的写法
        # my_dic[i[0].encode('UTF-8')] = i[1].encode('UTF-8')  # 这里将获得的数据由unicode类型转换为str类型,然后存入字典中
    host = my_dic['host']
    password = my_dic['password']
    port = int(my_dic['port'])

    def conn_db(self):
        LogPrint().info("----------------正在连接redis服务器----------------")
        r = redis.Redis(host=self.host, port=self.port)
        LogPrint().info("----------------连接服务器成功----------------")
        return r

    @staticmethod
    def operate(
            *dim):  # 这里可变参数dim至少有2个值,第一个是操作类型如set、get等,第二个是name值,第三个是value值可不传
        r = RedisDeal().conn_db()
        list_one = []
        for i in dim:
            list_one.append(i)

        if list_one[0] == 'set':
            r.set(name=list_one[1], value=list_one[2])
        elif list_one[0] == 'delete':
            r.delete(list_one[1])
        elif list_one[0] == 'get':
            return r.get(name=list_one[1])
        else:
            LogPrint().info("----------------操作类型或key值错误----------------")

    @staticmethod
    def close_db():
        r = RedisDeal().conn_db()
        r.connection_pool.disconnect()
예제 #7
0
class MysqlDeal:
    lock = threading.Lock()

    dcc = DealCommonCfg()
    my_list = dcc.read_config('mysql')  # 获得配置文件中的信息内容
    my_dic = {}  # 将获得的内容转换为字典类型
    for i in my_list:
        my_dic[i[0]] = i[1]
    host = my_dic['host']
    user = my_dic['user']
    password = my_dic['password']
    port = int(my_dic['port'])
    charset = my_dic['charset']
    db = my_dic['db']

    def conn_db(self):
        # LogPrint().info("----------------正在连接mysql服务器----------------")
        conn = pymysql.connect(  # 连接数据库,其实就是建立一个pymysql.connect()的实例对象conn,该对象有commit()、rollback()、cursor()等属性
            host=self.host,
            user=self.user,
            password=self.password,
            port=self.port,
            charset=self.charset,
            db=self.db)
        # LogPrint().info("----------------连接mysql服务器成功----------------")
        cur = conn.cursor()  # 通过游标(指针)cursor的方式操作数据库,该代码作用是得到当前指向数据库的指针
        return conn, cur

    def select_db(self, conn, cur, sql):  # 查询数据库,查询条件中需要使用传入的参数
        self.lock.acquire()
        try:
            cur.execute(sql)
        except pymysql.err.InterfaceError:
            MysqlDeal.reconnection_db(conn, cur, sql)
        finally:
            self.lock.release()
        result = cur.fetchall()
        if len(result) == 0:
            # LogPrint().info("----------------查询结束,数据库无数据----------------")
            return 0
        else:
            return result

    def other_operate_db(self, conn, cur, sql):  # 增、删、改数据库的操作
        self.lock.acquire()  # 获取锁
        try:
            cur.execute(sql)
            conn.commit()
        except pymysql.err.InterfaceError:
            MysqlDeal.reconnection_db(conn, cur, sql)
        finally:
            self.lock.release()  # 释放锁

    @staticmethod
    def close_db(conn, cur):
        cur.close()
        conn.close()

    # 数据库断开异常时,用来重连
    @staticmethod
    def reconnection_db(conn, cur, sql):
        conn.ping(reconnect=True)
        cur.execute(sql)
        conn.commit()
예제 #8
0
class InterfaceDeal:
    # s = requests.session()
    # s.keep_alive = False  # 关闭多余连接

    md = MysqlDeal()
    conn, cur = md.conn_db()

    dcc = DealCommonCfg()
    my_list = dcc.read_config('operating_environment')          # 获得配置文件中的信息内容
    my_dic = {}                                                 # 将获得的内容转换为字典类型
    for i in my_list:
        my_dic[i[0]] = i[1]
    host = my_dic['one_test_host']

    assert_result = ''                                          # 接口请求返回的数据断言后的结果,三种类型success、fail、error
    response_last = ''                                          # 接口请求的最后结果,需要存储到数据库中的response字段的值

    def __init__(self, num, api_purpose, request_url, request_method, request_data_type, request_data,
                 check_point, test_describe, relevance_case):
        self.num = num                                          # 用例编号
        self.api_purpose = api_purpose                          # 接口名称
        self.api_host = self.host                               # 接口域名
        self.request_url = request_url                          # 接口地址
        self.request_method = request_method                    # 请求方法
        self.request_data_type = request_data_type              # 请求数据类型
        self.request_data = request_data                        # 请求数据
        self.check_point = check_point                          # 断言内容
        self.test_describe = test_describe                      # 测试描述
        self.relevance_case = relevance_case                    # 关联用例

    # 接口调用函数
    def interface_test(self):
        if self.request_method == 'POST' and self.request_data_type != 'File':
            assert_result = self.post_deal()
            return assert_result, self.response_last
        elif self.request_method == 'GET':
            assert_result = self.get_deal()
            return assert_result, self.response_last
        elif self.request_data_type == 'File':
            assert_result = self.post_deal()
            return assert_result, self.response_last
        else:
            LogPrint().info("----------------请求方法或类型有误----------------")

    def post_deal(self):
        data = eval(self.request_data)                                                            # 将str类型转换成字典类型
        payload = json.dumps(data)
        headers = {'content-type': "application/json"}
        # headers = InterfaceHeadDeal().sign_headers(payload, self.request_data_type)
        url = self.api_host + self.request_url
        LogPrint().info('-------------调用第' + self.num + '个测试用例的接口-------------:' + url)

        try:
            response = ''
            if self.request_data_type in ('Data', 'File'):
                response = requests.post(url=url, data=payload, headers=headers, timeout=5)
            elif self.request_data_type == 'Form':  # 以form形式发送post请求,只需将请求的参数构造成一个字典,传入给request.post()的data参数即可
                response = requests.post(url=url, data=data, timeout=5)

            status = response.status_code
            resp1 = response.text

            if status == 200:
                resp2 = CommonMethod.response_data_deal(resp1)  # 对接口返回的数据进行处理,如结果中存在转义字符需要存储到数据库中,则需要进行数据的相应处理
            else:
                resp2 = resp1                      # 如果接口请求是404、415等非正常的状态码,那么返回的数据就不需要进行处理,直接存入数据库中即可

            assert_result = self.common_code_one(status, resp2)
            self.response_last = resp2
            return assert_result

        except Timeout:
            assert_result = self.common_code_two(url)
            self.response_last = "null"
            return assert_result

    def get_deal(self):
        url = self.api_host + self.request_url
        LogPrint().info('-------------调用第' + self.num + '个测试用例的接口-------------:' + url)
        try:
            response = requests.get(url=url, params=self.request_data, timeout=5)
            status = response.status_code
            resp1 = response.text.encode("utf-8")
            # resp = response.read()

            if type(resp1 == "bytes"):
                resp1 = str(resp1, encoding="utf-8")
            assert_result = self.common_code_one(status, resp1)
            return assert_result

        except Timeout:
            assert_result = self.common_code_two(url)
            return assert_result

    # 公共函数,主要用于结果判断和处理
    def common_code_one(self, status, resp):
        sql = self.sql_deal('fail', resp)
        if status == 200:
            LogPrint().info('----------------返回结果成功----------------:' + resp)
            self.assert_deal(resp)
            if self.assert_result == 'success':
                LogPrint().info('----------------测试断言结果----------------:' + '第' + str(self.num) + '个测试用例断言:通过')
                sql = self.sql_deal('success', resp)
                self.md.other_operate_db(self.conn, self.cur, sql)
                assert_result = 'success'
            else:
                LogPrint().info('----------------测试断言结果----------------:' + '第' + str(self.num) + '个测试用例断言:失败')
                self.md.other_operate_db(self.conn, self.cur, sql)
                assert_result = 'fail'
        else:
            LogPrint().error('----------------返回结果失败----------------:' + '第' + str(self.num) +
                             '个测试用例的接口请求失败!! [ ' + str(status) + ' ], ' + resp)
            assert_result = 'error'
            self.md.other_operate_db(self.conn, self.cur, sql)
        return assert_result

    def common_code_two(self, url):
        LogPrint().error('----------------返回结果失败----------------:' + '第' + str(self.num) +
                         '个测试用例的接口请求超时响应,请注意!! [ ' + url + ' ]')
        assert_result = 'error'
        # 测试结果失败的用例信息存入数据库
        sql = self.sql_deal('fail', ' ')
        self.md.other_operate_db(self.conn, self.cur, sql)

        mail_title = '接口响应超时: ' + self.api_purpose + ':' + url
        MailSend().overtime_warn(mail_title)
        return assert_result

    """
    断言结果函数,断言的方式有两种,一种是code和msg的值断言(包括正常和异常断言),另一种是接口关键数据断言,校验具体返回的数据字段值,所以excel中的
    check_point数据格式必须是这三种:包含code、包含msg、或者"${openId}=test"格式,最后格式的符号和预期值可以变化
    """
    def assert_deal(self, resp):
        check_point_list = self.check_point.split(",")
        check_result_list = []
        for i in check_point_list:                                  # check_point中可能需要多个校验的数据,所以要用逗号分隔符对字符串进行切片
            if 'code' in i or 'msg' in i:                           # 这里是判断是否是code和msg断言,前两种是正常和异常的code、msg断言
                if i in resp:
                    check_result_list.append(True)
                else:
                    check_result_list.append(False)
            else:                                                   # 这种情况是接口关键数据断言,校验具体返回的数据字段值
                # i必须是'{"openId":"$openId"}'这种格式,这里是对excel中的check_point格式进行了转换,excel中的格式必须是"${openId}>0"这种
                i_one = i.split("{")
                i_two = i_one[1].split("}")
                i_three = '$' + i_two[0]
                i_four = str({i_two[0]: i_three})
                request_data_last = CommonMethod.request_data_deal(i_four, resp)

                i_nine = i_two[1]
                i_ten = i_nine.split("\"")[0]
                if i_ten[1] != '=' and i_ten[1] != '<' and i_ten[1] != '>':
                    i_five = i_ten[0]                                                # 断言语句中的符号
                    i_six = i_ten[1:]                                                # 断言语句中的预期数据字段值
                else:
                    i_five = i_ten[:2]
                    i_six = i_ten[2:]

                i_seven = eval(request_data_last)
                i_eight = i_seven[i_two[0]]                                          # 从resp中拿出来的需要校验的实际数据字段值

                if i_five == '>':
                    check_result_list.append(str(i_eight) > str(i_six))
                elif i_five == '<':
                    check_result_list.append(str(i_eight) < str(i_six))
                elif i_five == '=':
                    check_result_list.append(str(i_eight) == str(i_six))
                elif i_five == '>=':
                    check_result_list.append(str(i_eight) >= str(i_six))
                elif i_five == '<=':
                    check_result_list.append(str(i_eight) <= str(i_six))
                elif i_five == '!=':
                    check_result_list.append(str(i_eight) != str(i_six))
                else:
                    LogPrint().info('--------断言语句中的比较符号有误,暂时只支持6种,请核对!---------')

        if False in check_result_list:
            self.assert_result = 'fail'
        else:
            self.assert_result = 'success'

    def sql_deal(self, result, response):
        # 如果请求的接口关联用例的值不为空,则需要从数据库中查询该关联的用例url值, A接口关联B接口后,因为A执行之前其关联的B用例接口一定执行了,所以直接从数据库中查找即可
        if int(self.relevance_case) != 0:
            sql_two = 'select url from test_case where case_id = %d order by create_time desc ' \
                      'limit 1' % int(self.relevance_case)
            result = self.md.select_db(self.conn, self.cur, sql_two)
            relevance_case_url = result[0][0]               # 所关联的接口的url值,需要存储到数据库中relevance_case_url字段的值
        else:
            relevance_case_url = ""

        url = self.api_host + self.request_url

        create_time = datetime.datetime.now()
        center_temp = '\"'
        if center_temp in str(self.request_data):
            # 这里接口请求的参数中包含"符号,需要将这个符号转义,这里r的意思是原始字符串,r'\"'的意思就是\"的字符,不是转义的意思
            request_data_last = "\'" + str(self.request_data).replace(center_temp, r'\"') + "\'"
        else:
            request_data_last = "\'" + str(self.request_data) + "\'"

        if center_temp in str(self.check_point):
            check_point_last = "\'" + str(self.check_point).replace(center_temp, r'\"') + "\'"
        else:
            check_point_last = "\'" + str(self.request_data) + "\'"

        if result == 'success':
            status = 1
        else:
            status = 0
        # 这里需要将参数都加上''符号,不然在sql语句中不是string类型,如请求方法时post,在sql中需要变为'post'才正确
        sql = "insert into test_case(case_id,request_method,request_data_type,interface_name,url," \
              "request_data,assert_fail_reason,test_describe,status,response,relevance_case_url,create_time) " \
              "values(%d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)" % \
              (int(self.num), "\'" + self.request_method + "\'", "\'" + self.request_data_type + "\'", "\'" +
               self.api_purpose + "\'", "\'" + url + "\'", request_data_last, check_point_last, "\'" +
               self.test_describe + "\'", status, "\'" + response + "\'", "\'" + relevance_case_url + "\'", "\'" +
               str(create_time) + "\'")
        return sql