精华内容
下载资源
问答
  • 文章目录项目实战1、使用抓包结合postman实现如下功能1.1 phpwind论坛注册1.2 ...项目实战 1、使用抓包结合postman实现如下功能 1.1 phpwind论坛注册 1.2 phpwind论坛登录->发帖(帖子内容每次都不一样) ...

    项目实战

    1、使用抓包结合postman实现如下功能

    1.1 phpwind论坛注册
    1.2 phpwind论坛登录->发帖(帖子内容每次都不一样)

    实战地址:http://47.107.178.45/phpwind/index.php?m=bbs

    在这里插入图片描述

    2、获取token

     var token = responseBody.match(new RegExp(/name="csrf_token" value="(.+?)"/))[1];
     pm.globals.set("token",token);
    

    在这里插入图片描述

    3、登录论坛

    在这里插入图片描述

    4、项目实战接口源码

    {
    	"info": {
    		"_postman_id": "5f78663c-d674-4b33-845d-0baf7959b40c",
    		"name": "项目实战",
    		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
    	},
    	"item": [
    		{
    			"name": "论坛注册",
    			"event": [
    				{
    					"listen": "test",
    					"script": {
    						"id": "ae36924c-508a-4658-ab05-3f5e3dc2bb69",
    						"exec": [
    							"var username='yangchaoyi';",
    							"pm.globals.set(\"username\",username);",
    							"pm.globals.set(\"pwd\",\"123456\");",
    							"pm.globals.set(\"email\",\"1231231231231@qq.com\");"
    						],
    						"type": "text/javascript"
    					}
    				}
    			],
    			"request": {
    				"method": "POST",
    				"header": [
    					{
    						"key": "Content-Type",
    						"name": "Content-Type",
    						"value": "application/x-www-form-urlencoded",
    						"type": "text"
    					}
    				],
    				"body": {
    					"mode": "urlencoded",
    					"urlencoded": [
    						{
    							"key": "username",
    							"value": "{{username}}",
    							"type": "text"
    						},
    						{
    							"key": "repassword",
    							"value": "{{pwd}}",
    							"type": "text"
    						},
    						{
    							"key": "password",
    							"value": "{{pwd}}",
    							"type": "text"
    						},
    						{
    							"key": "email",
    							"value": "{{email}}",
    							"type": "text"
    						},
    						{
    							"key": "csrf_token",
    							"value": "{{token}}",
    							"type": "text"
    						}
    					]
    				},
    				"url": {
    					"raw": "http://47.107.178.45/phpwind/index.php?m=u&c=register&a=dorun",
    					"protocol": "http",
    					"host": [
    						"47",
    						"107",
    						"178",
    						"45"
    					],
    					"path": [
    						"phpwind",
    						"index.php"
    					],
    					"query": [
    						{
    							"key": "m",
    							"value": "u"
    						},
    						{
    							"key": "c",
    							"value": "register"
    						},
    						{
    							"key": "a",
    							"value": "dorun"
    						}
    					]
    				},
    				"description": "论坛注册"
    			},
    			"response": []
    		},
    		{
    			"name": "获取token",
    			"event": [
    				{
    					"listen": "test",
    					"script": {
    						"id": "b8f8cfca-2a2a-43eb-b2f4-f877dcbf5a13",
    						"exec": [
    							"//1、获取网站token",
    							"// var tmp = pm.response.text();",
    							"// var token = tmp.match(new RegExp(/name=\"csrf_token\" value=\"(.+?)\"/))[1];",
    							"// pm.globals.set(\"token\",token);",
    							"// console.log(pm.globals.get(\"token\"));",
    							"",
    							" var token = responseBody.match(new RegExp(/name=\"csrf_token\" value=\"(.+?)\"/))[1];",
    							" pm.globals.set(\"token\",token);"
    						],
    						"type": "text/javascript"
    					}
    				}
    			],
    			"request": {
    				"method": "GET",
    				"header": [],
    				"url": {
    					"raw": "http://47.107.178.45/phpwind/index.php?m=u&c=register",
    					"protocol": "http",
    					"host": [
    						"47",
    						"107",
    						"178",
    						"45"
    					],
    					"path": [
    						"phpwind",
    						"index.php"
    					],
    					"query": [
    						{
    							"key": "m",
    							"value": "u"
    						},
    						{
    							"key": "c",
    							"value": "register"
    						}
    					]
    				}
    			},
    			"response": []
    		},
    		{
    			"name": "登录论坛",
    			"request": {
    				"method": "POST",
    				"header": [
    					{
    						"key": "Content-Type",
    						"name": "Content-Type",
    						"value": "application/x-www-form-urlencoded",
    						"type": "text"
    					}
    				],
    				"body": {
    					"mode": "urlencoded",
    					"urlencoded": [
    						{
    							"key": "username",
    							"value": "{{username}}",
    							"type": "text"
    						},
    						{
    							"key": "password",
    							"value": "{{pwd}}",
    							"type": "text"
    						},
    						{
    							"key": "backurl",
    							"value": "http://47.107.178.45/phpwind/read.php?tid=66152&fid=64",
    							"type": "text"
    						},
    						{
    							"key": "invite",
    							"value": "",
    							"type": "text"
    						},
    						{
    							"key": "csrf_token",
    							"value": "{{token}}",
    							"type": "text"
    						}
    					]
    				},
    				"url": {
    					"raw": "http://47.107.178.45/phpwind/index.php?m=u&c=login&a=dorun",
    					"protocol": "http",
    					"host": [
    						"47",
    						"107",
    						"178",
    						"45"
    					],
    					"path": [
    						"phpwind",
    						"index.php"
    					],
    					"query": [
    						{
    							"key": "m",
    							"value": "u"
    						},
    						{
    							"key": "c",
    							"value": "login"
    						},
    						{
    							"key": "a",
    							"value": "dorun"
    						}
    					]
    				}
    			},
    			"response": []
    		},
    		{
    			"name": "发帖",
    			"request": {
    				"method": "POST",
    				"header": [
    					{
    						"key": "Content-Type",
    						"name": "Content-Type",
    						"value": "application/x-www-form-urlencoded",
    						"type": "text"
    					}
    				],
    				"body": {
    					"mode": "urlencoded",
    					"urlencoded": [
    						{
    							"key": "atc_title",
    							"value": "yangchaoyi",
    							"type": "text"
    						},
    						{
    							"key": "atc_content",
    							"value": "admin888",
    							"type": "text"
    						},
    						{
    							"key": "pid",
    							"value": "",
    							"type": "text"
    						},
    						{
    							"key": "tid",
    							"value": "",
    							"type": "text"
    						},
    						{
    							"key": "special",
    							"value": "default",
    							"type": "text"
    						},
    						{
    							"key": "reply_notice",
    							"value": "1",
    							"type": "text"
    						},
    						{
    							"key": "csrf_token",
    							"value": "{{token}}",
    							"type": "text"
    						}
    					]
    				},
    				"url": {
    					"raw": "http://47.107.178.45/phpwind/index.php?c=post&a=doadd&_json=1&fid=73",
    					"protocol": "http",
    					"host": [
    						"47",
    						"107",
    						"178",
    						"45"
    					],
    					"path": [
    						"phpwind",
    						"index.php"
    					],
    					"query": [
    						{
    							"key": "c",
    							"value": "post"
    						},
    						{
    							"key": "a",
    							"value": "doadd"
    						},
    						{
    							"key": "_json",
    							"value": "1"
    						},
    						{
    							"key": "fid",
    							"value": "73"
    						}
    					]
    				}
    			},
    			"response": []
    		}
    	],
    	"protocolProfileBehavior": {}
    }
    

    5、后续

    今天老师讲授的时候,发现这个网址不仅需要验证token还要验证status,所以上述方法是有bug的,但是总体方法是没问题的,后续待更新ing

    学如逆水行舟,不进则退
    
    展开全文
  • Pytest+Allure+Jenkins接口自动化项目实战(一)

    千次阅读 多人点赞 2020-01-20 13:09:08
    基于python+pytest+excel+allure框架的接口自动化测试初版已基本实现,包括基本配置读取、用例读取、用例执行、sql读取执行、前置数据准备、后置数据清理以及测试报告生成等,环境独立运行、项目独立运行、用例独立...

           经过一周多时间,基于python+pytest+excel+allure框架的接口自动化测试初版已基本实现,包括基本配置读取、用例读取、用例执行、sql读取执行、前置数据准备、后置数据清理以及测试报告生成等,环境独立运行、项目独立运行、用例独立运行、jenkins集成、邮件发送暂未实现,再后期版本会再次推出,现在把整个框架设计思路和想法分享给大家来参考和借鉴。希望大家也能提供更好的思路和方法帮助我进行优化改进。

           实战项目是三端交互的项目,所以在设计思路上要考虑多项目如何交互,目前只写了1个项目的,其它2个项目都预留了位置,后期直接添加就可以,思路一样。

    一、整个代码目录及介绍

    common

    request.py  封装post、get请求方法,供所有地方调用

    login.py 封装各项目、各种方式的登录方法,供所有地方调用

    readFile.py 封装读取yaml中配置文件、excel中测试用例方法,供所有地方调用

    execSql.py 封装sql操作增、删、改、查方法,供所有地方调用

    prefixSqlData.py 封装前置、后置公共sql,供所有地方调用

    assertion.py 封装断言方法,供所有用例中调用

    logs.py 封装日志方法,供所有地方调用

    config

    sql.yaml  前置数据sql语句、后置清理sql语句等

    test.yaml  test环境数据库配置、接口域名、测试账号、登录接口数据等

    uat.yaml  uat环境数据库配置、接口域名、测试账号、登录接口数据等

    testcase.xls  测试用例等

    testcase

    项目1

        用例1、用例2

    项目2

        用例1、用例2

    testcase.xls  接口测试用例等

    conftest.py  放置了登录获取token供所有用例调用

    run_all_case.py 执行所有测试用例并生成测试报告

    logs

    每天的日志数据

    report

    html  测试报告index.html

    二、yaml文件基本配置

    项目一:
       url: 'https://www.baidu.com/'
       headers:
            Content-Type: 'application/json'
            Authorization: 'token'
       account:
         a_account: '17900000000'
         b_account: '18000000000'
         c_account: '19900000000'
         c_account1: '19900000001'
    
       c_login:
         method: post
         url: '/user/login'
         param:
            type: "7"
            login_from: 7
            mobile: "18888888888"
            code: "123456"
       c_sms_code:
         method: post
         url: '/1.0/users/login'
    
    
    
       mysql:
         host: 127.0.0.1
         user: test
         pwd: test
         test_db: user
    
    
    
    项目二:
      url: 'https://www.baidu.com/'

    三、yaml文件sql配置

    项目一:
      查id:
        - select_list
        - select id from A.B where create_mobile={}
      查用户id:
        - select_list
        - select id from A.B where mobile={}
      查团队id:
        - select_list
        - select id from A.B where company_user_id=(select id from A.B where mobile={})
      查C端用户id:
        - select_list
        - select user_id from A.B where mobile in({})
      解除用户:
        - update
        - update A.B set status=2 where mobile={}
    
    项目二:
      查id:
        - select_list
        - select id from A.B where create_mobile={}
      查用户id:
        - select_list
        - select id from A.B where mobile={}
      查团队id:
        - select_list
        - select id from A.B where company_user_id=(select id from A.B where mobile={})
      查C端用户id:
        - select_list
        - select user_id from A.B where mobile in({})
      解除用户:
        - update
        - update A.B set status=2 where mobile={}

    四、读取yaml文件、excel用例文件

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    import yaml,os,sys,xlwt,xlrd
    from common.logs import Log
    
    class ReadFile(object):
        log = Log()
        _instance=None
        def __new__(cls,*args,**kwargs):
            if cls._instance is None:
                cls._instance=super().__new__(cls)
            return cls._instance
    
        def __init__(self):
            self.excel_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config/testcase.xls')
            self.yaml_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config/test.yaml')
            self.sql_yaml_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config/sql.yaml')
    
        def read_yaml(self,path_type):
            """
            读yaml文件
            :return:
            """
            try:
                if path_type=='yaml_path':
                    file_path=self.yaml_path
                elif path_type=='sql_yaml_path':
                    file_path=self.sql_yaml_path
    
                with open(file_path,'r',encoding='utf-8') as f:
                    return yaml.load(f.read())
            except Exception as e:
                self.log.error("读yaml文件报错{}".format(e))
    
        def read_excel(self,sheet_name,function,casename=None):
            """
            读取excel
            :param sheet_name:
            :param function:
            :return:
            """
            try:
                book=xlrd.open_workbook(self.excel_path)
                sheet=book.sheet_by_name(sheet_name)
                param=[]
                for i in range(0,sheet.nrows):
                    if casename==None:
                        if sheet.row_values(i)[0]==function and sheet.row_values(i)[3]==1:
                            param.append(sheet.row_values(i))
                    else:
                        if sheet.row_values(i)[0]==function and sheet.row_values(i)[1]==casename and sheet.row_values(i)[3]==1:
                            param.append(sheet.row_values(i))
                return param
            except Exception as e:
                self.log.error("读取excel报错{}".format(e))
    
    
    if __name__ == '__main__':
        test=ReadFile()
        print(test.read_excel('lxk','我的','全部页面'))

    五、用例模板如下

    根据每个sheet存放不同项目的测试用例,然后根据再根据sheet去读取对应项目模块的测试用例

    Function模块、CaseName测试用例名、Type请求类型、Run是否执行、URL接口地址、Headers请求头、Param请求参数、SQL1、SQL2、SQL3测试中需用到的前置数据或后置数据、AssertType断言类型,因为接口返回的响应数据可能会多种多样,所以这里断言分了几种情况、Expect1预期结果1、Expect2预期结果2、Expect3预期结果3

    六、request方法

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    import requests,urllib3
    from urllib3 import encode_multipart_formdata
    from common.logs import Log
    
    class RunMethod(object):
        """
        request
        """
        log = Log()
        urllib3.disable_warnings()
    
    
        def post_main(self,url,data,header,file=None):
            """
            post请求
            :param url:
            :param data:
            :param header:
            :param file:
            :return:
            """
            res=None
            if file!=None:
                res=requests.post(url=url,json=data,headers=header,verify=False)
            else:
                res = requests.post(url=url, json=data,headers=header, files=file, verify=False)
            return res.json()
    
        def get_main(self,url,header,param=None):
            """
            get请求
            :param url:
            :param header:
            :param param:
            :return:
            """
            res=None
            if param!=None:
                res=requests.get(url=url,headers=header,verify=False)
            else:
                res = requests.get(url=url, headers=header, json=param,verify=False)
            return res.json()
    
        def run_main(self,method,url,header,data=None,file=None):
            """
            被调用主request
            :param method:
            :param url:
            :param header:
            :param data:
            :param file:
            :return:
            """
            try:
                res=None
                if method=='post' or method=='POST' or method=='Post':
                    res=self.post_main(url,data,header,file=None)
                elif method=='get' or method=='GET' or method=='Get':
                    res=self.get_main(url,header,param=None)
                else:
                    return "request传参错误"
                return res
            except Exception as e:
                self.log.error("请求方法报错{}".farmat(e))
    if __name__ == '__main__':
        print(111)

    七、登录方法

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    from common import request
    from common.readFile import ReadFile
    from common.logs import Log
    
    
    class Login(object):
        """
        登录
        """
        log = Log()
        request = request.RunMethod()
    
        def __init__(self):
            self.yaml_data = ReadFile().read_yaml('yaml_path')['lxk']
            self.header = self.yaml_data['headers']
            self.url = self.yaml_data['url']
            self.lxk_c_url = self.yaml_data['c_login']['url']
            self.lxk_c_method = self.yaml_data['c_login']['method']
            self.lxk_c_param = self.yaml_data['c_login']['param']
    
    
        def lxk_c_login(self,project,mobile):
            """
            蓝薪卡C端登录
            :param project:
            :param mobile:
            :return:
            """
            try:
                if project=='lxk_c':
                    self.lxk_c_param['mobile']=mobile
                    result=self.request.run_main(self.lxk_c_method, self.url+self.lxk_c_url, self.header, self.lxk_c_param)
                elif project=='lxk_a':
                    pass
                elif project=='lxk_b':
                    pass
                return result
            except Exception as e:
                self.log.error('登录报错{}'.format(e))
    
    if __name__ == '__main__':
        test=Login()
        print(test.lxk_c_login('lxk_c','18221124104'))
    

    八、操作sql方法

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    from common.readFile import ReadFile
    import pymysql
    import sys
    from common.logs import Log
    
    
    
    class ExecSql(object):
        """
        执行sql语句类
        """
        log = Log()
    
        _instance=None
        def __new__(cls,*args,**kwargs):
            if cls._instance is None:
                cls._instance=super().__new__(cls)
            return cls._instance
    
        def __init__(self):
            """
            初始化mysql配置
            :param platform_name:
            """
            #self.sql_conf = self._get_sql_conf(platform_name)
            self.sql_conf=None
    
        def _get_sql_conf(self, project):
            """
            获取mysql配置
            :param platform_name:
            :return:
            """
            try:
                return ReadFile().read_yaml('yaml_path')[project]['mysql']
            except:
                self.log.error("找不到对应项目:{0}".format(project))
    
        def connect_db(self):
            """
            连接mysql
            :return:
            """
            host = self.sql_conf['host']
            user = self.sql_conf['user']
            pwd = self.sql_conf['pwd']
            test_db = self.sql_conf['test_db']
            try:
                self.conn = pymysql.connect(host=host, user=user, password=pwd, db=test_db, port=3306, charset="utf8")
            except Exception as e:
                self.log.error("连接mysql失败:{0}".format(e))
    
        def get_cursor(self):
            """
            获取游标
            :return:
            """
            self.cursor=self.conn.cursor()
            return self.cursor
    
        def exec_sql(self,project,sql_type,sql):
            """
            执行sql语句
            :param sql_type:
            :param sql:
            :return:
            """
            self.sql_conf = self._get_sql_conf(project)
            try:
                if sql_type == 'select_one':
                    self.connect_db()
                    cursor = self.get_cursor()
                    cursor.execute(sql)
                    result = cursor.fetchone()
                elif sql_type == 'select_list':
                    self.connect_db()
                    cursor = self.get_cursor()
                    cursor.execute(sql)
                    result = cursor.fetchall()
                elif sql_type == 'update' or sql_type == 'del' or sql_type == 'insert':
                    self.connect_db()
                    result = self.get_cursor().execute(sql)
                self.conn.commit()
                self.cursor.close()
                self.conn.close()
                return result
            except Exception as e:
                self.log.error("执行sql语句报错:{0}".format(e))
    
    
    if __name__ == '__main__':
        test = ExecSql()
        a=test.exec_sql('lxk',"select_list","sql)
        print(aaa)

    九、日志方法

    #!/usr/bin/env python
    # _*_coding:utf-8 _*_
    import os, time, logging
    log_path=os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'logs')
    if not os.path.exists(log_path): os.mkdir(log_path)
    
    
    class Log(object):
        """
        log日志类
        """
    
        def __init__(self):
            self.logname = os.path.join(log_path, '%s.log' % time.strftime('%Y_%m_%d'))
            self.logger = logging.getLogger()
            self.logger.setLevel(logging.DEBUG)
            self.formatter = logging.Formatter('[%(asctime)s]-%(filename)s]-%(levelname)s:%(message)s')
    
        def __console(self, level, message):
            fh=logging.FileHandler(self.logname, 'a', 'utf-8')
            fh.setLevel(logging.DEBUG)
            fh.setFormatter(self.formatter)
            self.logger.addHandler(fh)
            ch = logging.StreamHandler()
            ch.setLevel(logging.INFO)
            ch.setFormatter(self.formatter)
            self.logger.addHandler(ch)
            if level == 'info':
                self.logger.info(message)
            elif level == 'debug':
                self.logger.debug(message)
            elif level == 'warning':
                self.logger.warning(message)
            elif level == 'error':
                self.logger.error(message)
            self.logger.removeHandler(ch)
            self.logger.removeHandler(fh)
            fh.close()
    
        def debug(self, message):
            self.__console('debug', message)
    
        def info(self, message):
            self.__console('info', message)
    
        def warning(self, message):
            self.__console('warning', message)
    
        def error(self, message):
            self.__console('error', message)
    
    
    if __name__ == '__main__':
        log = Log()
        log.info("---测试---")

    十、断言方法

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    from common.execSql import ExecSql
    from common.logs import Log
    
    class Assertion(object):
        log=Log()
        sql_values_list = []
        response_values = []
    
        def __init__(self):
            self.test=ExecSql().exec_sql
    
        def get_sql_data(self,project,sql_type,sql):
            '''
            查询sql数据组合list
            :param project:
            :param sql_type:
            :param sql:
            :return:
            '''
            try:
                sql_values=self.test(project,sql_type,sql)
                for i in sql_values:
                    for j in i:
                        self.sql_values_list.append(j)
            except Exception as e:
                self.log.error("查询sql数据组合list报错{}".format(e))
    
    
        def get_response_data(self,response_data, keys=[]):
            '''
            获取接口响应数据组合list
            :param response_data:
            :param keys:
            :return:
            '''
            try:
                if isinstance(response_data, list):
                    for value in response_data:
                        if isinstance(value, list) or isinstance(value, dict):
                            self.get_response_data(value, keys)
                elif isinstance(response_data, dict):
                    for i, j in sorted(response_data.items()):
                        if i in keys:
                            self.response_values.append(j)
                        else:
                            self.get_response_data(j, keys)
                else:
                    pass
            except Exception as e:
                self.log.error("获取接口响应数据组合list报错{}".format(e))
    
        def asser(self,function,casename,expect,response_data,assert_type=None):
            '''
            断言
            :param assert_type:
            :param expect:
            :param response_data:
            :return:
            '''
            try:
                if assert_type=='type1':
                    assert self.sql_values_list==self.response_values
                    self.log.info("查询sql数据组合list为{}".format(self.sql_values_list))
                    self.log.info("接口响应数据组合list为{}".format(self.response_values))
                assert eval(expect)['code'] == response_data['code']
                assert eval(expect)['msg'] == response_data['msg']
                self.log.info("{}——{}【PASS】".format(function,casename))
            except Exception as e:
                self.log.error("{}——{}【PASS】{}".format(function,casename,e))
    
    if __name__ == '__main__':
        # sql="sql"
        # test=Assertion()
        # test.get_sql_data(self,project,sql_type,sql)
        self.log.error("查询sql数据组合list报错{}".format(e))

    十一、conftest登录获取token

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    import pytest,os,yaml,requests
    from common.readFile import ReadFile
    from common.login import Login
    
    yaml_data=ReadFile().read_yaml('yaml_path')
    
    @pytest.fixture(scope='session')
    def get_lxk_c_headers():
        """
        登录获取token更新headers
        :return:
        """
        headers=yaml_data['lxk']['headers']
        token=Login().lxk_c_login('lxk_c',yaml_data['lxk']['account']['c_account'])['data']['token']
        headers['Authorization']=token
        return headers

    十二、测试用例方法

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    
    import pytest
    from common.readFile import ReadFile
    from common.request import RunMethod
    from common.assertion import Assertion
    from common.execSql import ExecSql
    from common.prefixSqlData import MakeSqlData
    import allure
    
    data = ReadFile().read_excel('lxk', '我的报名')
    
    @pytest.mark.parametrize('function,casename,type,run,url,hearders,param,sql1,sql2,sql3,asserttype,expect1,expect2,expect3',data)
    class Test(object):
        '''我的报名'''
    
        request = RunMethod().run_main
        assertion = Assertion()
        exec_sql = ExecSql().exec_sql
        yaml_data = ReadFile().read_yaml('yaml_path')['lxk']
        sql_yaml_data = ReadFile().read_yaml('sql_yaml_path')['lxk']
        prefix_sql_data = MakeSqlData('lxk').make_sql_data
    
    
        def setup_class(self):
            '''
            数据初始化
            :return:
            '''
            prefix_data=self.prefix_sql_data(self.yaml_data['account']['b_account'], self.yaml_data['account']['c_account'])
            company_id = self.exec_sql('lxk', self.sql_yaml_data['查企业id'][0], self.sql_yaml_data['查企业id'][1].format(self.yaml_data['account']['b_account']))[0][0]
            task_id = self.exec_sql('lxk', self.sql_yaml_data['查任务id'][0], self.sql_yaml_data['查任务id'][1].format(self.yaml_data['account']['b_account']))[0][0]
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],1))
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],2))
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],3))
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],4))
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],5))
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],7))
            self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'], 8))
    
        def teardown_class(self):
            '''
            数据清理
            :return:
            '''
            self.exec_sql('lxk', self.sql_yaml_data['删除已报名任务'][0], self.sql_yaml_data['删除已报名任务'][1].format(self.yaml_data['account']['c_account']))
            self.exec_sql('lxk', self.sql_yaml_data['解除用户团队'][0], self.sql_yaml_data['解除用户团队'][1].format(self.yaml_data['account']['c_account']))
    
        #@allure.feature('蓝薪卡')
        @allure.story('lxk_我的报名')
        def test_apply_task(self,get_lxk_c_headers,function,casename,type,run,url,hearders,param,sql1,sql2,sql3,asserttype,expect1,expect2,expect3):
            '''
            我的报名
            :param get_lxk_c_headers:
            :param function:
            :param casename:
            :param type:
            :param run:
            :param url:
            :param hearders:
            :param param:
            :param sql1:
            :param sql2:
            :param sql3:
            :param asserttype:
            :param expect1:
            :param expect2:
            :param expect3:
            :return:
            '''
            response_data = self.request(type,self.yaml_data['url']+url,get_lxk_c_headers,eval(param))
            self.assertion.get_sql_data('lxk',eval(sql1)[0],eval(sql1)[1].format(self.yaml_data['account']['c_account']))
            self.assertion.get_response_data(response_data,eval(expect2))
            self.assertion.asser(function,casename,expect1,response_data,asserttype)
    
    
    
    if __name__ == "__main__":
        pytest.main(["-s", "test_001_applyTask.py"])

    十三、run_all_case主程序执行入口

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    import pytest,os,allure
    if __name__ == "__main__":
    
        pytest.main(['-s',''])
        #生成测试报告json
        pytest.main(["-s", "-q", '--alluredir', 'C:/Users/wangli/PycharmProjects/PytestAutomation/report/result'])
        #将测试报告转为html格式
        split='allure '+'generate '+'C:/Users/wangli/PycharmProjects/PytestAutomation/report/result '+'-o '+'C:/Users/wangli/PycharmProjects/PytestAutomation/report/html '+'--clean'
        os.system('cd C:/Users/wangli/PycharmProjects/PytestAutomation/report')
        os.system(split)
        print(split)
    

    十四、测试报告如下

    展开全文
  • 上周和大家分享了Python+uiautomator2+weditor UI自动化测试实战(1):环境搭建,接下来和大家分享一下在具体的实战中的UI自动化的运用吧。 下面的代码主要演示了登录腾讯视频,然后切换到个人中心页面,用QQ登录后再...

    上周和大家分享了Python+uiautomator2+weditor UI自动化测试实战(1):环境搭建,接下来和大家分享一下在具体的实战中的UI自动化的运用吧。
    下面的代码主要演示了登录腾讯视频,然后切换到个人中心页面,用QQ登录后再登出的操作,里面用到了大部分的元素定位方法,如果大家想深入学习可以点击元素定位学习

    import uiautomator2 as u2
    from time import sleep
    
    # 手机的IP
    d = u2.connect('192.168.0.xxx')
    
    # 启动App
    d.app_start("com.tencent.qqlive")
    sleep(10)
    
    # 点击切换到'我的'页面
    d.click(0.813, 0.966)
    
    # 点击'点击登录'
    d(text="点击登录").click()
    
    # 点击'QQ登录'
    d.xpath('//*[@resource-id="com.tencent.qqlive:id/qt"]/android.view.ViewGroup[1]/android.support.v7.widget.RecyclerView[1]/android.view.ViewGroup[3]').click()
    d(text="QQ登录").click()
    sleep(3)
    # 输入QQ账号密码
    d(resourceId="com.tencent.mobileqq:id/name").send_keys('1122213213')
    d(resourceId="com.tencent.mobileqq:id/password").send_keys('ssijj3344')
    d(resourceId="com.tencent.mobileqq:id/login").click()
    
    #滑屏操作
    d.drag(0.652, 0.76, 0.66, 0.743,1)
    
    #点击'设置'
    d(text="设置").click()
    d.drag(0.73, 0.492,0.722, 0.452,1)
    sleep(3)
    d.drag(0.688, 0.814,0.704, 0.789)
    
    #点击'退出账号'
    d(resourceId="com.tencent.qqlive:id/cfg").click()
    sleep(2)
    d(text="退出登录").click()
    

    大家可以根据具体的项目需求运用到实际项目中去

    展开全文
  • selenium自动化测试实战

    万次阅读 多人点赞 2018-01-13 21:19:08
    一句话,自动化测试工具。它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个 Selenium 的插件,那么便可以方便地实现Web界面的测试。 Selenium 2,又名 ...

    一、Selenium介绍
    Selenium 是什么?一句话,自动化测试工具。它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个 Selenium 的插件,那么便可以方便地实现Web界面的测试。
    Selenium 2,又名 WebDriver,它的主要新功能是集成了 Selenium 1.0 以及 WebDriver(WebDriver 曾经是 Selenium 的竞争对手)。也就是说 Selenium 2 是 Selenium 和 WebDriver 两个项目的合并,即 Selenium 2 兼容 Selenium,它既支持 Selenium API 也支持 WebDriver API。
    中文文档:http://selenium-python-zh.readthedocs.io/en/latest/index.html
    英文文档:http://selenium-python.readthedocs.io/index.html

    二、python、pycharm安装
    Python官网下载链接:
    https://www.python.org/downloads/windows/
    pycharm官网下载链接:https://www.jetbrains.com/pycharm/download/#section=windows

    三、selenium安装
    1)pip install selenium
    安装Chrome driver
    https://chromedriver.storage.googleapis.com/index.html?path=2.29/
    Chrome浏览器和Chromedriver版本号:

    chromedriver版本 支持的Chrome版本
    v2.43 v69-71
    v2.42 v68-70
    v2.41 v67-69
    v2.40 v66-68
    v2.39 v66-68
    v2.38 v65-67
    v2.37 v64-66
    v2.36 v63-65
    v2.35 v62-64
    v2.34 v61-63
    v2.33 v60-62
    v2.32 v59-61
    v2.31 v58-60
    v2.30 v58-60
    v2.29 v56-58
    v2.28 v55-57
    v2.27 v54-56
    v2.26 v53-55
    v2.25 v53-55
    v2.24 v52-54
    v2.23 v51-53
    v2.22 v49-52
    v2.21 v46-50
    v2.20 v43-48
    v2.19 v43-47
    v2.18 v43-46
    v2.17 v42-43
    v2.13 v42-45
    v2.15 v40-43
    v2.14 v39-42
    v2.13 v38-41
    v2.12 v36-40
    v2.11 v36-40
    v2.10 v33-36
    v2.9 v31-34
    v2.8 v30-33
    v2.7 v30-33
    v2.6 v29-32
    v2.5 v29-32
    v2.4 v29-32

    2)把chromedriver.exe拷贝到到chrome的安装目录下…\Google\Chrome\Application\ ,同时把chrome的安装目录加入到path环境变量。

    四、自动测试实战:12306订票
    1.知识点
    Selenium定位web元素的方法
    浏览器调试工具使用

    2.步骤
    1) 人工走一遍流程,对自动化的流程心中有数
    2) 按步骤拆分,然后对每一个小步骤编写自动化脚本
    3) 将所有步骤合起来,多次运行,测试脚本

    3.打开12306

    #打开网址
    driver.get('https://kyfw.12306.cn/otn')
    #睡五秒自动选择验证码
    time.sleep(5)
    

    4.登录12306
    1)在chrome界面,按F12快捷键,弹出chrome的调试工具
    2)找出登录按钮的id和username、password的id
    根据id定位元素

    driver.find_element_by_id("username").click()
    driver.find_element_by_id("username").send_keys("5xxxx68397@qq.com")
    driver.find_element_by_id("password").send_keys("***")
    print("continue")
    time.sleep(15)
    

    根据链接的文本来定位元素

    driver.find_element_by_link_text("车票预订").click()
    time.sleep(5)
    

    在这里插入图片描述

    选择出发地
    这里写图片描述
    **利用js代码冻结浏览器界面。
    setTimeout(function(){debugger;}, 5000)
    **

    #出发地选择
    driver.find_element_by_id("fromStationText").click()
    # setTimeout(function(){debugger;}, 5000)
    driver.find_element_by_css_selector(u"[title=广州]").click()
    
    time.sleep(5)
    

    在这里插入图片描述

    右击代码位置,选择copy selector这里写图片描述

    在这里插入图片描述

    这里写图片描述
    选择出发日
    这里写图片描述这里写图片描述
    选择车次类型:
    五、实验分析:
    1、不会破解12306的变态验证码。没有自动破解验证码,所以留五秒钟自己手动选验证码。
    2、因为是学生认证所以多一步需要确认(不是学生可去掉)
    3、订票成功

    六、总结
    自动化测试的优点是能够很快、很广泛地查找缺陷,同时可以做很多重复性的工作,在回归测试阶段,我们可以利用自动化功能测试工具进行,而无须大量的软件测试人员手动的再次执行测试用例,极大的提高了工作效率。
    自动化测试的缺点也很明显,它们只能检查一些比较主要的问题,如崩溃、死机,但是却无法发现一些一般的日常错误,这些错误通过人眼很容易找到,但机器却往往找不到。另外,在自动测试中编写测试脚本工作量也很大,有时候该工作量甚至超过了手动测试的时间。
    Selenium脚本的执行速度受多方面因素的影响,如网速,操作步骤的繁琐程度,页面加载的速度,以及我们在脚本中设置的等待时间,运行脚本的线程数等。所以不能单方面追求运行速度的,要确保稳定性,能稳定地实现回归测试才是关键。
    Selenium保证元素成功率是通过元素的定位,当然它的定位方法很多,一定能有合适的。但是在自动化工程的实施过程中,高质量的自动化测试不是只有测试人员保证的。需要开发人员规范开发习惯,如给页面元素加上唯一的name,id等,这样就能大大地提高元素定位的准确性。

    附代码:

    #-*-coding:utf8-*-
    import time
    from selenium import webdriver
    
    #运行chrome,打开浏览器
    driver =webdriver.Chrome()
    #设置浏览器窗口
    driver.set_window_size(1080,800)
    
    #设置全局操作时间
    driver.implicitly_wait(10)
    
    #打开网址
    driver.get('https://kyfw.12306.cn/otn')
    
    time.sleep(5)
    
    driver.find_element_by_link_text("账号登录").click()
    driver.find_element_by_id("J-userName").click()
    driver.find_element_by_id("J-userName").send_keys("5xxx68397@qq.com")
    driver.find_element_by_id("J-password").send_keys("***")
    print("continue")
    #睡十五秒自动选择验证码 app扫码登陆
    time.sleep(15)
    
    driver.find_element_by_link_text("车票预订").click()
    time.sleep(5)
    #出发地选择
    driver.find_element_by_id("fromStationText").click()
    # setTimeout(function(){debugger;}, 5000)
    driver.find_element_by_css_selector(u"[title=广州]").click()
    
    time.sleep(5)
    #目的地选择
    driver.find_element_by_id("toStationText").click()
    driver.find_element_by_css_selector(u"[title=北京]").click()
    time.sleep(5)
    
    #出发日期选择
    driver.find_element_by_id("train_date").click()
    driver.find_element_by_css_selector("body > div.cal-wrap > div:nth-child(1) > div.cal-cm > div:nth-child(24) > div").click()
    time.sleep(5)
    
    #车型选择
    driver.find_element_by_css_selector("#_ul_station_train_code > li:nth-child(1) > label").click()
    time.sleep(5)
    
    while True:
        try:
            driver.find_element_by_id("query_ticket").click()
            e=driver.find_element_by_id("SWZ_6i00000G720F")
            e.click()
            if e.text in [u'无','--']:
                print ("nono")
                time.sleep(1)
            else:
                print("yes")
                # 购票
                driver.find_element_by_link_text("预订").click()
                # 乘车人选择
                driver.find_element_by_css_selector("#normal_passenger_id > li:nth-child(1) > label").click()
                # 学生票确认(不是学生可去掉)
                driver.find_element_by_link_text("确认").click()
                # 提交订单
                driver.find_element_by_link_text("提交订单").click()
                driver.find_element_by_link_text("确认").click()
        except:
            pass
    
    展开全文
  • 电商项目Web自动化测试实战

    千次阅读 2020-02-26 16:56:54
    电商项目自动化测试实战 前言: Web自动化主要是功能自动化和部分功能的兼容性测试 Web自动化主要针对:主要流程和重要功能的自动化(有效等价类、异常场景) 测试准备: TPshop开源电商项目 测试业务场景: 登录-&...
  • Python3 接口自动化测试项目实战一(WEB项目)

    千次阅读 热门讨论 2019-01-13 21:58:32
    1.1 接口测试项目搭建 1.1.1 教育局招生管理系统部署 教育局招生管理系统是基于java+mysql,下面介绍它的部署过程。 1.从我的网盘下载部署文件。   2.安装jdk以及配置环境变量。 点击文件进行安装。   下...
  • 以编写最优化的自动化测试用例代码 你基本可以搞定任何Selenium面试,并能从设计阶段开始领导整个Selenium自动化项目 你应该能够使用应用程序的GUI来验证数据完整性 你将能够创建漂亮的报告来打动客户或领导 更深入...
  • docker自动化部署实战

    万次阅读 多人点赞 2017-09-10 18:49:20
    docker自动化部署实战避免重复造轮子,我就不说docker的好处了,百度一大堆,况且你能看到这个文章,说明你也大概了解docker了。当然还是要从安装开始一步步来,本文中使用的是daocloud+coding+docker。daocloud官网...
  • 2019 Python接口自动化测试框架实战开发(一)

    万次阅读 多人点赞 2019-06-28 15:55:25
    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!...整个项目分为四个部分:接口基础丶接口开发丶Unittest与接口测试结合以及接口自动化框架从设计到开发 接口基础包括:H...
  • commmod模块续集,接python+selenium 自动化测试框架+项目实战(2) b funciton模块 功能:该模块是公共的测试用例模块,实现截图,查找最新的测试报告,将最新的测试报告最为邮件发送这三个功能 1、截图保存到指定的...
  • 统一功能测试(UFT)是一个著名的功能测试商业测试工具。它为跨平台的桌面、网络和移动应用程序的应用编程接口、网络服务和图形用户界面...该工具具有先进的基于图像的对象识别功能、可重复使用的测试组件和自动化文档。
  • 通常而言,激光雷达和...然而,无人车安装的传感器数量较多,高效且自动化地完成多传感器标定对于自动驾驶研发而言非常关键,本文介绍一种自动化标定相机-激光雷达的方法,并且给出了相对完整的ROS实现以供读者参考。
  • 本套框架实现了appium全自动执行,多台设备同时执行,自动启服务,自动生成testng文件,监听,重连.......只需写测试脚本 编写脚本顺序:page、action、test 本次实战以“联通手机营业厅app”为例进行脚本编写,...
  • 之前的文章说过, 要写一篇自动化实战的文章, 这段时间比较忙再加回家过11一直没有更新,今天整理一下实战项目的代码共大家学习。
  • 写一个完整的自动化测试项目框架,供大家一起学习和探讨 思路:自动化测试项目的框架需要能够便于维护,无人值守,自动执行,有对应的 测试报告和测试结果 解决方案: 1、尽可能的做到数据与脚本的分离,使用数据...
  • 讲解基于Python Selenium 的自动化数据采集,自动化框架设计,SEO搜索收录引擎与接口对接等实战项目
  • Python+Requests接口自动化测试实战

    千次阅读 2019-11-27 20:18:22
    Python+Requests接口自动化测试实战 接口自动化的工具有很多,本文主要讲述用Python+Requests实现接口自动化测试。 环境搭建 1,首先你的电脑安装python环境,可以参考:python3安装教程 2,安装requests库,你...
  • Mock+Proxy在SDK项目自动化测试实战

    千次阅读 2016-10-18 10:47:10
    项目背景广告SDK项目是为应用程序APP开发人员提供移动广告平台接入的API程序集合,其形态就是一个植入宿主APP的jar包。提供的功能主要有以下几点: - 为APP请求广告内容 - 用户行为打点 - 错误日志打点 - 反作弊...
  • Selenium自动化测试实战项目(一)

    千次阅读 2017-01-04 09:45:52
    这个项目是使用了axatrikx集成的框架,官方:http://axatrikx.com/category/automation-testing/selenium-webdriver,在这个框架上,...项目名字是master,里面有2个子项目 1.framework里面的框架内部的封装的方法 2.t
  • Web自动化测试实战(一)

    万次阅读 多人点赞 2019-08-23 15:41:39
    一丶认识web自动化测试 1. 什么是自动化测试? 2.为什么进行自动化测试? 3.自动化测试的分类 二丶元素定位 1.为什么要学习定位元素? 2.元素定位的工具或手段有哪些? 3.环境及工具 4.css选择器 一丶认识web...
  • 自动化测试项目实战训练【广州8月】: http://www.automationqa.com/training-info/alltraininginfo/item/184-automation-training-2011-8.html
  • Python+Django+Ansible Playbook自动化运维项目实战 一、入门引导 DevOPS DevOps(英文Development和Operations的组合)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和...
  • Appium自动化测试实战

    千次阅读 2017-11-25 12:46:46
    Appium 是一个开源并且跨平台的,支持多种脚本语言(java,Python,C#等等)适用于原生的或混合的移动应用(hybrid mobile apps)的自动化测。Appium的使用原理是通过WebDriver来 驱动安卓或者iOS移动应用. 二,工作...
  • 自动化接口实战(二)

    万次阅读 2019-09-03 18:45:30
    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! ... 目录 一丶JMeter介绍及安装 ...二丶JMeter接口自动化 1.jmeter中的元件 2.jmeter实战 一丶JMeter介绍及安装 1....
  • 完整的框架源码下载...一、Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建_00——框架结构简解 首先配置好开发环境,下载安装Python并...
  • 给出的框架思路,编写了一个简单的自动化测试项目供大家参考,共同学习 1、driver模块 功能:驱动浏览器 代码如下: #coding=utf-8 from selenium import webdriver def browser(): driver=webdriver.Fire...
  • 本文将通过讲解一个主流电商平台的购物全流程,展示自动化从脚本开发、用例设计、报告输出的全流程,适合从事功能测试多年,想快速转化到自动化测试的测试人员以及想深入了解自动化架构的测试人员、以及想了解 Web ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 81,213
精华内容 32,485
关键字:

自动化项目实战