def __init__(self): self.con = pymysql.connect(host=conf.get('database', 'host'), port=conf.getint('database', 'port'), user=conf.get('database', 'user'), password=conf.get('database', 'password'), charset='utf8', cursorclass=pymysql.cursors.DictCursor)
def stu_login_fixture(): driver = create_driver(is_headers=True) driver.maximize_window() driver.implicitly_wait(15) url = eval(conf.get('url', 'url')) driver.get(url) login=LoginPage(driver) mobile=conf.get('test_data', 'mobile_stu') pwd = conf.get('test_data', 'pwd_stu') login.login(mobile,pwd) yield driver driver.quit()
def admin_login(cls): url = conf.get('env', 'base_url') + '/member/login' params = { 'mobile_phone': conf.get('test_data', 'admin_phone'), 'pwd': conf.get('test_data', 'admin_pwd') } headers = eval(conf.get('env', 'headers')) response = requests.post(url=url, json=params, headers=headers) res = response.json() print(res) admin_token = jsonpath(res, '$..token')[0] headers['Authorization'] = 'Bearer ' + admin_token cls.headers_admin = headers cls.member_id_admin = jsonpath(res, '$..id')[0]
def test_withdraw(self, item): url_withdraw = self.base_url + item['url'] method = item['method'].lower() # 用上面得到的用户id替换测试用例中的用户id # item['data'] = item['data'].replace('##member_id##', str(self.member_id)) # 调用封装的替换方法,用测试类对象的member_id值替换用例数据中的字符串 item['data'] = data_replace(item['data'], TestWithdraw) # 请求参数 params_withdraw = eval(item['data']) # %%%%%%%%%%%%%%%%%%%请求接口之前查询用户的余额%%%%%%%%%%%%%%%% sql = 'SELECT leave_amount FROM futureloan.member WHERE mobile_phone={}'.format( conf.get('test_data', 'mobile_phone')) # %%%%%%%%%%%%%%%%%%%请求接口之前查询用户的余额%%%%%%%%%%%%%%%% start_amount = self.db.find_one(sql)['leave_amount'] # 请求接口,获得返回值 response_withdraw = requests.request(method, url=url_withdraw, json=params_withdraw, headers=self.headers) actual_withdraw = response_withdraw.json() # %%%%%%%%%%%%%%%%%%%请求接口之前查询用户的余额%%%%%%%%%%%%%%%% end_amount = self.db.find_one(sql)['leave_amount'] expected_withdraw = eval(item['expected']) try: assert_dict_in(expected_withdraw, actual_withdraw) # 运行成功的用例中,判断提现前的金额减去提现后的金额是否等于用例中的提现金额 if item['flag']: self.assertEqual(params_withdraw['amount'], float(start_amount - end_amount)) except AssertionError as e: log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行通过'.format(item['title']))
def user_login(cls): url = conf.get('env', 'base_url') + '/member/login' # 从配置文件读取登录接口所需要的参数mobile_phone和pwd params = { 'mobile_phone': conf.get('test_data', 'mobile_phone'), 'pwd': conf.get('test_data', 'pwd') } headers = eval(conf.get('env', 'headers')) # 请求登录接口 response = requests.post(url=url, json=params, headers=headers) res = response.json() # 从接口响应信息里面提取token和member_id token = jsonpath(res, '$..token')[0] cls.member_id = jsonpath(res, '$..id')[0] # 将提取出来的token存储在对象headers中 headers['Authorization'] = 'Bearer ' + token cls.headers = headers
def test_login_error(self, cases, open_browser): driver = open_browser url = eval(conf.get('url', 'url')) driver.get(url) l_page = LoginPage(driver) l_page.login(cases['mobile'], cases['pwd']) actual = l_page.get_error_text() assert cases['expected'] in actual
class TestLogin(unittest.TestCase): # 创建一个读取Excel的对象 excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'login') # 利用创建的对象调用读取Excel方法 cases = excel.read_excel() # 从配置文件读取项目的基本地址 base_url = conf.get('env', 'base_url') headers = eval(conf.get('env', 'headers')) @list_data(cases) def test_login(self, item): # 接口请求地址 url_login = self.base_url + item['url'] # 接口请求参数 params = eval(item['data']) # 请求方法,并转换为小写 method = item['method'].lower() # 从配置文件获取请求头 # 获取期望值 expected_login = eval(item['expected']) # 请求接口,返回实际结果 response_login = requests.request(method=method, url=url_login, headers=self.headers, json=params) actual_login = response_login.json() # 获取用例的行号 # row = item['case_id'] + 1 # 捕获异常 try: assert_dict_in(expected_login, actual_login) except AssertionError as e: # 往Excel中写入执行结果 # self.excel.write_excel(row=row, column=6, value='失败', font=openpyxl.styles.Font(color='FF0000')) # 往日志文件中写入执行结果 log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: # self.excel.write_excel(row=row, column=6, value='通过', font=openpyxl.styles.Font(color='339966')) log.info('这是【{}】用例执行通过'.format(item['title']))
class TestWithdraw(unittest.TestCase, BaseTest): # 从Excel读取用例数据 excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'withdraw') cases = excel.read_excel() # 从配置文件获取基础路径和请求头 base_url = conf.get('env', 'base_url') # 创建操作数据库对象 db = OptionDB() @classmethod def setUpClass(cls): # 创建测试类对象,赋值为从已封装的登录接口提取的headers和member_id cls.user_login() @list_data(cases) def test_withdraw(self, item): url_withdraw = self.base_url + item['url'] method = item['method'].lower() # 用上面得到的用户id替换测试用例中的用户id # item['data'] = item['data'].replace('##member_id##', str(self.member_id)) # 调用封装的替换方法,用测试类对象的member_id值替换用例数据中的字符串 item['data'] = data_replace(item['data'], TestWithdraw) # 请求参数 params_withdraw = eval(item['data']) # %%%%%%%%%%%%%%%%%%%请求接口之前查询用户的余额%%%%%%%%%%%%%%%% sql = 'SELECT leave_amount FROM futureloan.member WHERE mobile_phone={}'.format( conf.get('test_data', 'mobile_phone')) # %%%%%%%%%%%%%%%%%%%请求接口之前查询用户的余额%%%%%%%%%%%%%%%% start_amount = self.db.find_one(sql)['leave_amount'] # 请求接口,获得返回值 response_withdraw = requests.request(method, url=url_withdraw, json=params_withdraw, headers=self.headers) actual_withdraw = response_withdraw.json() # %%%%%%%%%%%%%%%%%%%请求接口之前查询用户的余额%%%%%%%%%%%%%%%% end_amount = self.db.find_one(sql)['leave_amount'] expected_withdraw = eval(item['expected']) try: assert_dict_in(expected_withdraw, actual_withdraw) # 运行成功的用例中,判断提现前的金额减去提现后的金额是否等于用例中的提现金额 if item['flag']: self.assertEqual(params_withdraw['amount'], float(start_amount - end_amount)) except AssertionError as e: log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行通过'.format(item['title']))
def add_project(cls): url_add = conf.get('env', 'base_url') + '/loan/add' params_add = { "member_id": cls.member_id, "title": "蓝色水汀的项目", "amount": 2000, "loan_rate": 12.0, "loan_term": 6, "loan_date_type": 1, "bidding_days": 5 } response_add = requests.post(url=url_add, json=params_add, headers=cls.headers) res_add = response_add.json() cls.loan_id = jsonpath(res_add, '$..id')[0]
class TestAudit(unittest.TestCase, BaseTest): excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'audit') cases = excel.read_excel() base_url = conf.get('env', 'base_url') db = OptionDB() @classmethod def setUpClass(cls): # 创建测试类对象,赋值为从已封装的登录接口提取的普通用户headers_normal和member_id # 封装的登录接口提取的管理员headers_admin和member_id_admin cls.user_login() cls.admin_login() def setUp(self): self.add_project() @list_data(cases) def test_audit(self, item): url_audit = self.base_url + item['url'] method = item['method'] expected = eval(item['expected']) item['data'] = data_replace(item['data'], TestAudit) params = eval(item['data']) response_audit = requests.request(method=method, url=url_audit, json=params, headers=self.headers_admin) res_audit = response_audit.json() print(res_audit) if res_audit['msg'] == 'OK' and item['title'] == "审核通过": TestAudit.pass_loan_id = params['loan_id'] # setattr(TestAudit,'pass_loan_id',params['loan_id']) try: self.assertEqual(expected['code'], res_audit['code']) self.assertEqual(expected['msg'], res_audit['msg']) if item['flag']: sql = 'SELECT status FROM futureloan.loan WHERE id={}'.format( self.loan_id) status = self.db.find_one(sql)['status'] self.assertEqual(expected['status'], status) except AssertionError as e: log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行成功'.format(item['title']))
def test_login_pass(self, cases, open_browser): expect = cases['expected'] driver = open_browser url = eval(conf.get('url', 'url')) driver.get(url) login_page = LoginPage(driver) login_page.login(cases['mobile'], cases['pwd']) index_page = IndexPage(driver) res = index_page.is_login_success() try: assert res == expect except AssertionError as e: log.error('【登录成功的用例】————>执行失败') log.exception(e) raise e else: log.info('【登录成功的用例】————>执行通过')
class TestGetInfo(unittest.TestCase,BaseTest): base_url = conf.get('env', 'base_url') @classmethod def setUpClass(cls): cls.user_login() def test_getinfo(self): url_getinfo = self.base_url + '/member/{}/info'.format(self.member_id) response = requests.get(url=url_getinfo, headers=self.headers) actual = response.json() expected = {"code": 0, "msg": "OK"} try: assert_dict_in(expected, actual) except AssertionError as e: log.error('获取用户信息失败') log.exception(e) raise e else: log.info('获取用户信息成功')
class TestAdd(unittest.TestCase, BaseTest): excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'add') cases = excel.read_excel() base_url = conf.get('env', 'base_url') db = OptionDB() @classmethod def setUpClass(cls): # 创建测试类对象,赋值为从已封装的登录接口提取的headers_normal和member_id cls.user_login() @list_data(cases) def test_add(self, item): url_add = self.base_url + item['url'] method = item['method'] # item['data'] = item['data'].replace('##member_id##', str(self.member_id)) # 调用封装的替换方法,用测试类对象的member_id值替换用例数据中的字符串 item['data'] = data_replace(item['data'], TestAdd) params_add = eval(item['data']) expected = eval(item['expected']) sql = 'select * from futureloan.loan where member_id={}'.format( self.member_id) start_count = self.db.find_count(sql) response_add = requests.request(method=method, url=url_add, json=params_add, headers=self.headers) res_add = response_add.json() end_count = self.db.find_count(sql) try: assert_dict_in(expected, res_add) if item['flag']: self.assertEqual(1, end_count - start_count) else: self.assertEqual(0, end_count - start_count) except AssertionError as e: log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行成功'.format(item['title']))
class TestUpdate(unittest.TestCase, BaseTest): excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'update') cases = excel.read_excel() base_url = conf.get('env', 'base_url') db = OptionDB() @classmethod def setUpClass(cls): # 创建测试类对象,赋值为从已封装的登录接口提取的headers和member_id cls.user_login() @list_data(cases) def test_update(self, item): url_update = self.base_url + item['url'] method_update = item['method'].lower() # item['data'] = item['data'].replace('##member_id##', str(self.member_id)) # 调用封装的替换方法,用测试类对象的member_id值替换用例数据中的字符串 item['data'] = data_replace(item['data'], TestUpdate) params_update = eval(item['data']) response_update = requests.request(method=method_update, url=url_update, json=params_update, headers=self.headers) res_update = response_update.json() sql = 'select * from futureloan.member where reg_name="{}"'.format( params_update.get('reg_name', "")) count = self.db.find_count(sql) expected_update = eval(item['expected']) try: assert_dict_in(expected_update, res_update) if item['flag']: self.assertEqual(1, count) except AssertionError as e: log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行成功'.format(item['title']))
def data_replace(data, cls): """ 替换数据方法 :param data: 要进行替换的用例数据(字符串) :param cls: 测试类 :return: 返回用例数据 """ while re.search('##(.+?)##', data): # 扫描整个data字符串,返回第一个成功匹配的字符串 res = re.search('##(.+?)##', data) # 显示匹配到的第一个字符串内容 item = res.group() # 显示匹配到的第一个字符串第一个括号里面的内容 attr = res.group(1) try: # 从用例数据中获取值 value = getattr(cls, attr) except AttributeError: # 从配置文件中获取值 value = conf.get('test_data', attr) # 用获取的值替换字符串 data = data.replace(item, str(value)) return data
def setUp(self): # -----------------------通过继承的父类BaseTest调用添加项目方法--------------------------------- self.add_project() # -------------------------------审核项目—————————————————————— url_audit = conf.get('env', 'base_url') + '/loan/audit' # 判断当运行第5条用例时,审核不通过 if TestInvest.casecnt == 4: params_audit = { "loan_id": self.loan_id, "approved_or_not": False, } else: params_audit = { "loan_id": self.loan_id, "approved_or_not": True, } requests.patch(url=url_audit, json=params_audit, headers=self.headers_admin) # 判断当运行第11条用例时,手动更新项目的状态,将状态设置为3 if TestInvest.casecnt == 10: sql1 = 'update futureloan.loan set status=3 where id={}'.format(self.loan_id) self.db.update(sql1) TestInvest.casecnt += 1
fh.setLevel(fh_level) # 将日志输出渠道绑定到日志收集器上 log.addHandler(fh) # 输出日志到控制台 # 创建一个输出到控制台的输出渠道 sh = logging.StreamHandler() # 设置输出到控制台的日志level sh.setLevel(sh_level) # 将日志输出渠道绑定到日志收集器上 log.addHandler(sh) # 设置输出的日志格式 formats = '%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s' # 创建格式对象 log_format = logging.Formatter(formats) # 为输出渠道设置输出格式 sh.setFormatter(log_format) fh.setFormatter(log_format) # 返回一个日志收集器 return log # 创建日志对象,加载配置文件中的日志配置 log = creat_log( name=conf.get('logging', 'name'), level=conf.get('logging', 'level'), # 将日志保存至指定的目录中 filename=os.path.join(Log_Path, conf.get('logging', 'filename')), fh_level=conf.get('logging', 'fh_level'), sh_level=conf.get('logging', 'sh_level'))
class TestInvest(unittest.TestCase, BaseTest): """ 继承父类unittest.TestCase和BaseTest """ excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'invest') cases = excel.read_excel() base_url = conf.get('env', 'base_url') db = OptionDB() @classmethod def setUpClass(cls): # 用例的类前置,继承了父类BaseTest的方法和对象 cls.user_login() cls.admin_login() # 定义一个类属性计数,用来判断哪些用例需要执行某个条件,哪些用例不需要 cls.casecnt = 0 def setUp(self): # -----------------------通过继承的父类BaseTest调用添加项目方法--------------------------------- self.add_project() # -------------------------------审核项目—————————————————————— url_audit = conf.get('env', 'base_url') + '/loan/audit' # 判断当运行第5条用例时,审核不通过 if TestInvest.casecnt == 4: params_audit = { "loan_id": self.loan_id, "approved_or_not": False, } else: params_audit = { "loan_id": self.loan_id, "approved_or_not": True, } requests.patch(url=url_audit, json=params_audit, headers=self.headers_admin) # 判断当运行第11条用例时,手动更新项目的状态,将状态设置为3 if TestInvest.casecnt == 10: sql1 = 'update futureloan.loan set status=3 where id={}'.format(self.loan_id) self.db.update(sql1) TestInvest.casecnt += 1 @list_data(cases) def test_invest(self, item): url_invest = self.base_url + item['url'] method = item['method'] expected = eval(item['expected']) item['data'] = data_replace(item['data'], TestInvest) params = eval(item['data']) # 在投资表里查询该项目投资前的数量 sql_invest = 'select * from futureloan.invest where loan_id={}'.format(self.loan_id) count_start = self.db.find_count(sql_invest) # 在用户表里查询投资用户投资前的可用余额 sql_amount = "select leave_amount from futureloan.member where id='{}'".format(self.member_id) amount_start = self.db.find_one(sql_amount)['leave_amount'] # 在流水表中查询投资人在投资该项目前的数据数量 sql_finance = 'select * from futureloan.financelog where pay_member_id={}'.format(self.member_id) cnt_start = self.db.find_count(sql_finance) # 请求接口,获取响应值 response_invest = requests.request(method=method, url=url_invest, json=params, headers=self.headers) res_invest = response_invest.json() # 当用例数据的flag有值时,从投资响应结果中提取投资id,然后在回款列表查询回款记录数量 if item['flag']: invest_id = jsonpath(res_invest, '$..id')[0] sql_repay = 'select * from futureloan.repayment where invest_id={}'.format(invest_id) self.count_repay = self.db.find_count(sql_repay) # 在投资表里查询该项目投资后的数量 count_end = self.db.find_count(sql_invest) # 在用户表里查询投资用户投资后的可用余额 amount_end = self.db.find_one(sql_amount)['leave_amount'] # 在流水表中查询投资人在投资该项目后的数据数量 cnt_end = self.db.find_count(sql_finance) # 在项目表中,查询该项目的当前状态 sql_status = 'select status from futureloan.loan where id={}'.format(self.loan_id) actual_status = self.db.find_one(sql_status)['status'] try: self.assertEqual(expected['code'], res_invest['code']) self.assertIn(expected['msg'], res_invest['msg']) # 当运行第一条用例时,判断回款记录数是否和预期的数量一致 if self.casecnt == 1: self.assertEqual(6, self.count_repay) # 当用例数据的flag有值时,进行以下断言 if item['flag']: # 断言投资成功后,投资表里有没有多1条数据 self.assertEqual(1, count_end - count_start) # 断言投资成功后,用户投资前可用余额减去投资后可用余额是否等于投资金额 self.assertEqual(params['amount'], float(amount_start - amount_end)) # 断言投资成功后,流水表是不是多了一条数据 self.assertEqual(1, cnt_end - cnt_start) # 断言投资成功后,项目的实际状态和预期状态是否一致 self.assertEqual(expected['status'], actual_status) except AssertionError as e: log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行成功'.format(item['title']))
class TestRegister(unittest.TestCase): # 创建一个读取Excel的对象 excel = ReadExcel(os.path.join(Data_Path, 'cases.xlsx'), 'register') # 利用创建的对象调用读取Excel方法 cases = excel.read_excel() # 从配置文件读取项目的基本地址 base_url = conf.get('env', 'base_url') # 请求头 headers = eval(conf.get('env', 'headers')) # 创建操作数据库对象 db = OptionDB() def random_phone(self): phone = random.randint(15300000000, 15399999999) return phone @list_data(cases) def test_register(self, item): # 第一步:准备用例数据 # 1、接口请求地址 url_register = self.base_url + item['url'] # 2、接口请求参数 if '##mobile_phone##' in item['data']: # 给测试类TestRegister动态设置对象mobile_phone,且对象值为随机方法生成的数值 setattr(TestRegister, 'mobile_phone', self.random_phone()) # 调用封装的替换方法,用测试类对象的mobile_phone值替换用例数据中的字符串 item['data'] = data_replace(item['data'], TestRegister) # phone = self.random_phone() # item['data'] = item['data'].replace('##mobile_phone##', str(phone)) params = eval(item['data']) print(params) # 3、请求方法,并转换为小写 method = item['method'].lower() # 4、从配置文件获取请求头 # 5、获取期望值 expected_register = eval(item['expected']) # 第二步:请求接口,获取返回实际结果 response_register = requests.request(method, url_register, headers=self.headers, json=params) actual_register = response_register.json() # 从数据库中查询注册数据数量,字典的get方法,在参数中查找键mobile_phone,找不到时用""替代 sql = 'select * from futureloan.member where mobile_phone="{}"'.format( params.get('mobile_phone', "")) res1 = self.db.find_count(sql) # 第三步:断言,捕获异常 try: # 断言实际结果是否包含预期结果 assert_dict_in(expected_register, actual_register) # 判断用例是否需要进行数据库校验 if item['flag']: # 从数据库中查询出的数据条数和1对比,如果有1条,则注册成功 self.assertEqual(1, res1) except AssertionError as e: # 往日志文件中写入执行结果 log.error('这是【{}】用例执行失败'.format(item['title'])) log.exception(e) raise e else: log.info('这是【{}】用例执行通过'.format(item['title']))