寫了項目的一個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)
大致的結構就是這樣了,不知道說明白了沒。。。。。。接下來就是引入測試報告。明天說。