写了项目的一个demo,目前只写了其中的一个模块(product),目录结构如下
common主要放一些公共方法,
common
----parseconfig 是解析ini用
----s_packaging 封装的一些方法 conf
conf 配置文件
----config.ini 公共配置数据
----config.py 环境变量配置
financial 财务模块
product 商品模块
----product.ini 商品数据文件
----test_category.py 测试用例文件
conftest 固件函数
pytest.ini 执行配置文件 暂时还没用到
最后的执行用例test_category.py ,这些实现的目的,主要是为了方便用例的易读性。让初级测试也能知道每一步到底是做了什么。
# coding:utf-8
"""
author:zhouxuan
@project--file : erp2 -->test_category.py
2019/12/31 10:35
@Desc:分类管理
"""
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.parseconfig import parseConfig
from common.s_packaging import packaging
from conf.config import PRODUCT_DIR,COMMON_DIR
import os
class Test_Category():
@pytest.mark.parametrize('login',[('商品管理','分类管理')],indirect=True)
def test_add(self,login):
driver=login
product=packaging('test_cateorgy',PRODUCT_DIR)
product.click_obj(driver,'添加分类')
product.write_obj(driver,'分类名称','通信产品')
product.write_obj(driver,'显示顺序',1)
product.write_obj(driver,'中文报关名称','小米手机')
product.write_obj(driver,'英文报关名称','mi9max')
product.click_obj(driver,'保存(新增)')
success=packaging('common',COMMON_DIR)
success.wait_element_appear(driver,'成功提示')
if __name__ == '__main__':
pytest.main(['-s','test_category.py'])
用例对应的测试界面如下
再结合conftest中的login,用例在引用固件login的时候,设置indirect为true,是为了将‘login’当做函数执行,且login中,有两个变量,所以我们也传递了两个变量('商品管理','分类管理')过去。
# coding:utf-8
"""
author:zhouxuan
@project--file : erp2 -->conftest.py
2019/12/31 9:57
@Desc:
"""
from selenium import webdriver
from conf.config import *
from selenium.webdriver.common.keys import Keys
import pytest
from selenium.webdriver.common.action_chains import ActionChains
import time
@pytest.fixture()
def login(request):
driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(2)
driver.get(SYS_URL)
driver.find_element(value='username').send_keys('*****')
driver.find_element(value='password').send_keys('******',Keys.ENTER)
time.sleep(6)
value= request.param
target_element=driver.find_element_by_link_text(value[0])
ActionChains(driver).move_to_element(target_element).perform()
driver.find_element_by_link_text(value[1]).click()
yield driver
# driver.quit()
再说明下最后的用例是如何实现的,可以看到用例都是调用了packaging()类,packaging类具体如下:
# coding:utf-8
"""
author:zhouxuan
2019/12/30 10:57
PyCharm 封装常用的方法
"""
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.remote.webdriver import By
from selenium.webdriver.common.keys import Keys
from common.parseconfig import parseConfig
class packaging():
def __init__(self,sections,ini_dir):
self.sections=sections
self.ini_dir=ini_dir
self.parse=parseConfig(self.sections,self.ini_dir)
def wait_element_appear(self,driver,ini_key,timeout=10):
by, value = self.parse.split_content(ini_key)
paraser_by(by)
WebDriverWait(driver, timeout, 1,).until(lambda x: x.find_element(eval(by),value).is_displayed())
def write_obj(self,driver,ini_key,*args):
by, value = self.parse.split_content(ini_key)
paraser_by(by)
driver.find_element(eval(by),value).send_keys(*args)
def click_obj(self,driver,ini_key):
by,value=self.parse.split_content(ini_key)
paraser_by(by)
driver.find_element(eval(by),value).click()
def waiting_obj(self,driver,ini_key):
by, value = self.parse.split_content(ini_key)
paraser_by(by)
self.wait_element_appear(self,driver, timeout=10, by=eval(by), value=value)
def paraser_by(by):
if by == 'By.XPATH':
by = By.XPATH
elif by == 'By.ID':
by = By.ID
elif by == 'By.NAME':
by = By.NAME
return by
if __name__ == '__main__':
click_obj('dfd',[1,2])
我们以def click_obj(self,driver,ini_key):
by,value=self.parse.split_content(ini_key)
paraser_by(by)
driver.find_element(eval(by),value).click()为例子说明
这里的操作就是找到元素,再点击。by为获取元素的方式by.id,by.xpath等,value就是对应的id,xpath的值了。by,value来自于
self.parse.split_content(ini_key)
self.parse=parseConfig(self.sections,self.ini_dir) 继续看parseConfig()
# coding:utf-8
"""
author:zhouxuan
@project--file : erp2 -->parseconfig.py
2019/12/31 15:01
@Desc:
"""
from configobj import ConfigObj
class parseConfig():
def __init__(self,section,config_dir):
"""
:param section: ini文件的主题
:param config_dir: ini文件的路径
"""
self.file=config_dir
self.section= section
self.configfile=ConfigObj(self.file,encoding='utf-8')
def get_all_sections(self):
#获取所有的section
return self.configfile.sections
def get_all_options(self):
#获取指定的section内容
return self.configfile[self.section]
def split_content(self,option):
#拆解对应的数据
section = self.section
try:
xpath_result = self.configfile[section][option]
if '$' in xpath_result:
xpath_result=self.configfile[section][xpath_result]
if '>>' in xpath_result:
return xpath_result.split('>>')
else:
return ['By.XPATH',xpath_result] #默认xpath格式
except Exception as e:
print ('error',e)
if __name__ == '__main__':
value = parseConfig('test_baidu')
print (value)
# print (value.get_all_sections())
# print (value.get_all_options())
print (value.split_content('设置'))
这里就是对ini文件的解析,我们看看ini文件的格式product.ini
[test_cateorgy]
添加分类=//*[@id="buttonFrame"]/div/ul/li/a
分类名称=//*[@id="category.categoryName"]/input
显示顺序=//*[@id="category.categoryOrder"]/input
中文报关名称=//*[@id="category.declareCnName"]/input
英文报关名称=//*[@id="category.declareEnName"]/input
保存(新增)=//span[@id="ButtonSave"]/a
保存并继续新建=//*[@id="ButtonSave_Continue"]/a
成功提示=//div[@class='mt5']//span[@class='ico_agreen left']
,我们以key,value的形式来说明,其中key就对应到了我们测试用例中的信息,value就是元素的路径,这里我默认的是xpath路径,如果是非xpath的时候,就要把方式和路径都写到ini文件中,并且用>>来分割,对应的代码就是这段
if '>>' in xpath_result:
return xpath_result.split('>>')
通过packaging类中的split_content的函数,返回的就是by,value了。把by value写过去,就能执行driver.find_element(eval(by),value).click()了。最后显示到脚本中的格式就变成了
product.click_obj(driver,ini文件中的key)
大致的结构就是这样了,不知道说明白了没。。。。。。接下来就是引入测试报告。明天说。