前言
最近學習完了requests、pytest,實踐出真知。下面以禪道為例。docker方式搭建禪道
一、Pycharm中創建項目結構
1.新建一個工程,工程名稱自己定義,如:zentao
2.在工程的根目錄下新建一個conftest.py(測試用例的一些fixture配置)和pytest.ini(改變pytest的運行方式)
3.在工程下創建以下package包:
--case:這個包放test開頭的測試用例,也可以放一些非test開頭的封裝接口方法
--common:這個包放一些公共的方法,如:讀取excel文件方法,讀取mysql、oracle的腳本
--config:放一些配置文件,如郵箱的一些參數:收件人,發件人,密碼等
4.在工程下創建以下文件夾:
--logs:這里存放日志信息
--report:這里存放測試報告
二、開始寫腳本
思考:1.登錄之后,需要提bug,然后操作bug,如何保持登錄了?s=requests.session()可以實現保持會話;
2.假如登錄,提bug,操作bug,都寫在一個.py文件,可以使用s.get(...),s.post(...)操作所有請求,那若是這些操作在不同的.py文件呢?fixture自定義測試用例前置條件可以實現; 作用范圍session(多個文件調用一次,可以跨.py文件調用),conftest.py文件在當前所在目錄及以下目錄生效;
3.若是請求地址寫死,線下線上切換不方便,怎么辦?當然fixture可以搞定了
2.1 由此,conftest.py腳本的內容確定了,如下:
#注意這里的ip改為自己服務器的ip哦
#conftest.py import requests import pytest @pytest.fixture(scope="session") def s(): ss=requests.session() return ss @pytest.fixture(scope="session") def host(): host="http://47.98.66.11:8899" return host
2.2 編寫登錄的腳本
# coding:utf-8 #test_login.py import re import pytest import hashlib import allure @allure.severity("blocker") @allure.epic("禪道登錄,增刪改查測試") @allure.feature("禪道登錄") @allure.issue("http://47.98.66.11:8899/bug-browse-1-0-all.html") class Test_login: @pytest.fixture() def getrand(self,s,host): while True: r = s.get(host+"/user-login.html") # print(r.text) rand = re.findall("id='verifyRand' value='(.+?)'", r.text) #print(rand) if len(rand[0])==10: #break print(rand[0]) return rand[0] @pytest.fixture() def md5(self,getrand): first=hashlib.md5("P@ssw0rd".encode('utf-8')).hexdigest()+getrand print(first) pwd=hashlib.md5(first.encode('utf-8')).hexdigest() print(pwd) return (getrand,pwd) @allure.title("登錄用例") def test_login(self,md5,s,host): data={"account":"admin", "password":md5[1], "passwordStrength":1, "referer":"/", "verifyRand":md5[0], "keepLogin":1} r=s.post(host+"/user-login.html",data=data) #print(r.__dict__) # print(dir(r)) # # print(r.text) r1=s.get(host+"/my/") #print(r1.text) assert '退出' in r1.text
2.3 提交bug
# coding:utf-8 #test_newbug.py import pytest import re import random import allure @pytest.fixture() def uppic_steps(s,host):#上傳圖片 f={"localUrl":"D:\\ch.jpg", "imgFile":("ch.jpg",open("D:\\ch.jpg","rb"),"image/jpeg")} r=s.post(host+"/file-ajaxUpload-5f37e08f8d109.html?dir=image",files=f) #print(r.text) print(r.json()) #picurl=re.findall(',"url":"(.+?)"}',r.text)[0].replace("\\","") picurl=r.json()["url"] print("上傳圖片地址:{}".format(picurl)) return picurl @pytest.fixture() def get_uid(s,host):#獲取uid r=s.get(host+"/bug-create-1-0-moduleID=0.html") uid=re.findall("kuid = '(.+?)'",r.text) return uid @allure.severity("critical") @allure.title("提bug") def test_newbug(s,uppic_steps,host,get_uid): data={"product":1, "module":0, "project":1, "openedBuild[]":"trunk", "assignedTo":"admin", "type":"codeerror", "title":"接口自動化bug0815_15_附圖片、附件:"+str(random.randint(0,1000)), "severity":3, "pri":3, "steps":"<p>[步驟]<img src={} alt="" /></p><br/><p>[結果]</p><br/><p>[期望]</p><br/>".format(uppic_steps), "oldTaskID":0, "status":"active", "uid":get_uid, "caseVersion":0, "case":0, "result":0, "testtask":0} f={ ("files[]",("中國氣候.jpg",open("D:\\中國氣候.jpg","rb"),"image/jpeg")), ("labels[]","中國氣候.jpg"), ("files[]",("hl.jpeg",open("D:\\hl.jpeg","rb"),"image/jpeg")), ("labels[]","hl.jpeg") } r=s.post(host+"/bug-create-1-0-moduleID=0.html",data=data,files=f) print("提交bug,響應內容:{}".format(r.text))
2.4 編輯bug-確認bug-解決bug-關閉bug
# coding:utf-8 #test_operate.py import pytest from lxml import etree import re import time import allure import random @pytest.fixture() def get_id(s,host):#查找未關閉狀態的第一條bug的id r=s.get(host+"/bug-browse-1-0-unclosed-0-id_desc.html") er=etree.HTML(r.text) id=er.xpath('//*[@id="bugList"]/tbody/tr[1]/td[1]/a')[0].text #查找第一個的id print("提取第一個id為:{}".format(id)) return id def get_idstatus(s,get_id,host):#根據id,獲取bug的狀態 r=s.get(host+"/bug-browse-1-0-all.html") er2=etree.HTML(r.text) idtitle=er2.xpath('//*[@id="bugList"]/tbody/tr[@data-id={}]/td[6]'.format(get_id))[0].get("title") print(get_id,idtitle) return idtitle @allure.title("修改bug") def test_edit(s,get_id,host): r=s.get(host+"/bug-edit-{}.html".format(get_id)) kuid=re.findall("var kuid = '(.+?)'",r.text) lasted=re.findall("id='lastEditedDate' value='(.+?)'",r.text) data = {"product": 1, "module": 0, "project": 1, "openedBuild[]": "trunk", "duplicateBug":0, "assignedTo": "admin", "deadline":"0000-00-00", "type": "codeerror", "title": "0818bug:" + str(random.randint(0, 1000)), "severity": 3, "pri": 3, "steps": "<p>[步驟]</p><br/><p>[結果]</p><br/><p>[期望]</p><br/>", "status": "active", "lastEditedDate":lasted, "uid": kuid, "caseVersion": 0, "comment":"修改bug"} s.post(r.url,data=data) assert get_idstatus(s, get_id, host)=="激活" @allure.title("確認bug") def test_confirm(s,get_id,host): r=s.get(host+"/bug-confirmBug-{}.html?onlybody=yes".format(get_id)) kuid = re.findall("var kuid = '(.+?)'", r.text)[0] data={ "assignedTo":"admin", "type":"codeerror", "pri":3, "status":"active", "comment":"ok,稍后修復", "uid":kuid } r1 = s.post(r.url, data=data) print("確認后,響應內容:{}".format(r1.text)) print(get_id) assert get_idstatus(s, get_id, host) == "激活" @allure.title("解決bug") def test_resolve(s,get_id,host):#解決bug r=s.get(host+"/bug-resolve-{}.html?onlybody=yes".format(get_id)) kuid=re.findall("var kuid = '(.+?)'",r.text)[0] print(type(kuid),kuid,r.url) datas={"resolution":"bydesign", "resolvedBuild":"trunk", "resolvedDate":time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()), "assignedTo":"admin", "status":"resolved", "comment":"不予修復", "uid":kuid } r1 = s.post(r.url, data=datas) print("修改為已解決,響應內容:{}".format(r1.text)) print(get_id) assert get_idstatus(s,get_id,host)=="已解決" @allure.title("關閉bug") def test_close(s,host,get_id):#關閉bug url=host+"/bug-close-{}.html?onlybody=yes".format(get_id) r=s.get(url) kuid=re.findall("kuid = '(.+?)'",r.text) data={ "status":"closed", "comment":"ok", "uid":"kuid" } r1=s.post(url,data=data) print(r1.text) assert get_idstatus(s,get_id,host)=='已關閉'
2.5 為了展示自己的勞動成果,報告是不可少的
#pytest.ini [pytest] #pytest-html生成報告 #addopts=-s --html=report/a.html --self-contained-html #allure-pytest 生成報告 addopts=-s --alluredir report/b
2.6 zentao文件下,打開cmd,執行pytest
pytest執行完畢,繼續輸入allure serve report/b 自動展示html格式報告(注意:report/b可以隨意命名,但必須與pytest.ini中的內容一致)
注意:pytest可以在zentao目錄下執行,也可以在case目錄下執行,但這樣report/b所在的目錄就不同了;根據pytest.ini,執行pytest會在pytest當前所在目錄生成report/b目錄,若是report/b不存在則直接創建,若是存在則使用已有的;
執行pytest時,一定要刪除b目錄,不然可能會產生冗余數據;
三、寫代碼過程中,想要調試某個腳本;如,提交bug;
那么需要執行登錄腳本和提交bug腳本;
在case目錄下,打開cmd,執行pytest -s test_login.py test_newbug.py
若是想要調試登錄,那直接執行pytest -s test_login.py