每日打卡-01-字符串填空
起止時間: 2020/10/19 09:00 ~ 2020/11/21 23:59
知識點參考 https://www.cnblogs.com/superhin/p/13837611.html
- 編寫一個函數,輸入一個text參數,將函數參數放入字符串 "//*[text()='所傳text參數']"指定位置中,並打印這個字符串
- 定義一個多行文本
tpl = '''
<html>
<head><meta charset="UTF-8"><title>title變量位置</title></head>
<body>
<h1>report_name變量位置</h1>
<div>開始時間:start_at變量位置 運行時間:duration變量位置 秒</div>
<div>總數:testRuns變量位置 通過:successes變量位置 失敗:failures變量位置 異常: errors變量位置</div>
</body>
<html>'''
已知變量
title="測試報告"
report_name="接口測試報告"
start_at="2020-09-10 10:00:00"
duration=3
testRuns=20
successes=15
failures=4
errors=1
把上述變量渲染到tpl模板變量中,並將得到的包含數據的字符串按保存文本文件的方式,以utf-8編碼的格式保存為一個名稱為report.html的文件。
參考答案
# 1
def xpath(text):
return f'//*[text()="{text}"]
# 2
tpl = '''
<html>
<head><meta charset="UTF-8"><title>{title}</title></head>
<body>
<h1>{report_name}</h1>
<div>開始時間:{start_at} 運行時間:{duration} 秒</div>
<div>總數:{testRuns} 通過:{successes} 失敗:{failures} 異常: {errors}</div>
</body>
<html>'''
title="測試報告"
report_name="接口測試報告"
start_at="2020-09-10 10:00:00"
duration=3
testRuns=20
successes=15
failures=4
errors=1
html = tpl.format(title=title, report_name=report_name, start_at=start_at, duration=duration,
testRuns=testRuns, successes=successes, failures=failures, errors=errors)
with open('report.html, 'w', encoding='utf-8') as f:
f.write(html)
每日打卡-02-列表和字典解包
起止時間: 2020/10/20 09:00 ~ 2020/11/21 23:59
知識點:https://www.cnblogs.com/superhin/p/13837849.html
- 有一個變量
search_ipt_loc = ('id', 'kw')
和函數
def find_element(by, value):
print(f'通過{by}={value}定位元素')
怎樣調用find_element函數將search_ipt_loc中的數據傳入?
- 有一個字典
db_conf = {'host': '127.0.0.1', 'port': 3306, 'user': 'test', 'password': '11111', 'db': 'abc'}
和函數
def connect(host,port,user,password,db):
print(f'連接數據{host}成功')
怎么調用函數把db_conf中的數據傳入?
參考答案
search_ipt_loc = ('id', 'kw')
def find_element(by, value):
print(f'通過{by}={value}定位元素')
db_conf = {'host': '127.0.0.1', 'port': 3306, 'user': 'test', 'password': '11111', 'db': 'abc'}
def connect(host,port,user,password,db):
print(f'連接數據{host}成功')
find_element(*search_ipt_loc)
connect(**db_conf)
每日打卡-03-使用對象在方法間共享屬性
起止時間: 2020/10/21 09:00 ~ 2020/11/21 23:59
知識點:https://www.cnblogs.com/superhin/p/13841854.html
- 設計一個名為Page的類,需要傳入一個名為driver的參數。其中包含以下3個方法。
(1)統一定位方法
def find_element(by, value):
...
by參數的選擇是"id","name","class name", "tag name", "link text", "partial link text", "xpath", "css selector"
value是具體對應的元素屬性或定位表達式字符串
當by=id時使用find_element_by_id方法定位,依次類推
並返回定位到的元素
(2)元素點擊方法
def click(by, value):
...
使用by,value調用上面封裝的find_element方法得到元素,然后進行點擊
(3)元素輸入方法
def type(by, value, text):
...
使用by,value調用上面封裝的find_element方法得到元素, 然后輸入text的值
完成后,在類下使用以下腳本進行測試
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
baidu = Page(driver)
baidu.type('id', 'kw', '簡書 韓志超')
baidu.click('id', 'su')
sleep(3)
driver.quit()
參考答案
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
class Page(object):
def __init__(self, driver: WebDriver):
self.driver = driver
def find_element(self, by: str, value: str) -> WebElement:
method_map = {
'id': self.driver.find_element_by_id,
'name': self.driver.find_element_by_name,
'class name': self.driver.find_element_by_class_name,
'tag name': self.driver.find_element_by_tag_name,
'link text': self.driver.find_element_by_link_text,
'partial link text': self.driver.find_element_by_partial_link_text,
'xpath': self.driver.find_element_by_xpath,
'css selector': self.driver.find_element_by_css_selector,
}
if by not in method_map:
raise ValueError('不支持該定位方法')
func = method_map.get(by)
element = func(value)
return element
def click(self, by: str, value: str) -> None:
print(f'點擊元素{by}={value}')
self.find_element(by, value).click()
def type(self, by: str, value: str, text: str) -> None:
print(f'元素{by}={value}中輸入{text}')
send_key = self.find_element(by, value)
send_key.send_keys(text)
if __name__ == '__main__':
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
baidu = Page(driver)
baidu.type("id", "kw", "簡書 韓志超")
baidu.click("id", "su")
sleep(3)
driver.quit()
每日打卡04-使用CSV數據
起止時間: 2020/10/22 09:00 ~ 2020/11/21 23:59
知識點:https://www.cnblogs.com/superhin/p/11495956.html
- 假設我們爬取到一批數據
movies = [
('肖申克的救贖','Tim Robbins', 'https://xiaoshenke.html'),
('霸王別姬','張國榮', 'https://bawangbieji.html'),
('阿甘正傳','Tom Hanks', 'https://aganzhengzhuan.html'),
]
將其保存為一個movie.csv文件,並加上標題行movie,player,url
2. 假設我們有一個data.csv文件,內容如下
a,b,excepted
1,2,3
0,0,0
-1,-1,-1
6,0.3,6.3
另外有一個函數
def add(a,b):
return a+b
編寫一個測試函數,讀取csv中的每行數據,將add(a,b)的返回結果與每行的excepted對比,如果成打印成功
失敗則打印失敗。
參考答案
import csv
# 1
movies = [
('肖申克的救贖','Tim Robbins', 'https://xiaoshenke.html'),
('霸王別姬','張國榮', 'https://bawangbieji.html'),
('阿甘正傳','Tom Hanks', 'https://aganzhengzhuan.html'),
]
header = ('movie','player','url')
with open('movie.csv', 'w', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(header)
writer.writerows(movies)
# 2
def add(a, b):
return a + b
with open('data.csv', encoding='utf-8') as f:
data = csv.reader(f)
for a, b, excepted in data:
a, b, excepted = float(a), float(b), float(excepted)
if add(a, b) == excepted:
print(f'{a}+{b}={excepted} 通過')
else:
print(f'{a}+{b}={excepted} 不通過')
每日打卡-05-兩數之和問題
起止時間: 2020/10/23 09:00 ~ 2020/11/21 23:59
知識點:時間復雜度指需要Operate操作的次數的量級
完全遍歷一個長度為n的列表則時間復雜度為O(n)。
如果雙重循環
for i in range(n):
for j in range(n):
....
則時間復雜度是O(n^2)
- 假設我們有一個列表
l=[1,2,3,4,5,6,7,8] 數據不重復,目標值為6,要求找出數組中兩個元素之和等於目標 的數組下標。
要求時間復雜度小於O(n^2)
參考答案
注意,不要使用雙重循環,暴力加和來和target對比,正確的做法是單層循環,然后查找target與當前值的差,是否存在於列表中。
但是由於列表的in查詢時間復雜度是O(n),即隱含了一層循環,這樣效率其實和雙重循環是一樣的,都是O(n^2)。
這里就可以使用哈希來優化查詢差值是否在列表中操作,將O(n)降為O(1),因此總體的效率就會變成O(n^2)->O(n)。
l = [1,2,3,4,5,6,7,8]
set1 = set(list1) # 使用集合已方便查找
target = 6
result = []
for a in list1:
b = target - a
if a < b < target and b in set1: # 在集合中查找,為避免重復,判斷a為較小的那個值
result.append((list1.index(a), list1.index(b))) # 列表index取下標的操作為O(1)
print(result)
每日打卡-06-列表字典推導式
起止時間: 2020/10/26 11:08 ~ 2020/10/31 23:59
知識點:https://www.cnblogs.com/superhin/p/13877327.html
- 數據篩選
假設一個活動列表接口數據如下
res = {
'code': 0,
'msg': '成功',
'datas': [
{'activityName': '雙11折扣', 'activityId': 12543, 'start_time': '20201020', 'end_time': '20201120', 'state': 1},
{'activityName': '今日折扣', 'activityId': 23413, 'start_time': '20201020', 'end_time': '20201021', 'state': 2},
{'activityName': '大減價', 'activityId': 13265, 'start_time': '20201019', 'end_time': '20201120', 'state': 0},
{'activityName': '每日促銷', 'activityId': 19876, 'start_time': '20201020', 'end_time': '20201121', 'state': 0},
{'activityName': '新用戶優惠', 'activityId': 15801, 'start_time': '20201020', 'end_time': '20201220', 'state': 1},
]
}
已知state=0為未開始,1為進行中,2為以結束,使用列表推導式得到當前所有進行中的activityId列表,要求每個activityId轉為字符串形式。
- Cookies格式轉化
假設我們需要通過登錄接口繞過Selenium登錄操作,我們需要使用requests發送登錄接口,得到響應中的cookies然后再使用driver.add_cookie
方法添加的瀏覽器中。
接口返回的cookies是一個字典格式,如{'Token', 'abcdefg', 'SessionID': '1234567'}
而selenium添加cookie時需要這樣的格式,{'name': 'Token': 'value': 'abcdefg'}
和{'name': 'SessionID': 'value': '123456'}
使用推導式實現完成轉換
cookies = {'Token':'abcdefg', 'SessionID': '1234567'}
# 轉為
cookies = [{'name': 'Token': 'value': 'abcdefg'},{'name': 'SessionID': 'value': '123456'}]
參考答案
# 1
res = {
'code': 0,
'msg': '成功',
'datas': [
{'activityName': '雙11折扣', 'activityId': 12543, 'start_time': '20201020', 'end_time': '20201120', 'state': 1},
{'activityName': '今日折扣', 'activityId': 23413, 'start_time': '20201020', 'end_time': '20201021', 'state': 2},
{'activityName': '大減價', 'activityId': 13265, 'start_time': '20201019', 'end_time': '20201120', 'state': 0},
{'activityName': '每日促銷', 'activityId': 19876, 'start_time': '20201020', 'end_time': '20201121', 'state': 0},
{'activityName': '新用戶優惠', 'activityId': 15801, 'start_time': '20201020', 'end_time': '20201220', 'state': 1},
]
}
activity_ids = [str(item.get('activityId') for item in res.get('datas', [])]
# 2
cookies = {'Token':'abcdefg', 'SessionID': '1234567'}
cookies = [{'name': key, 'value': value} for key, value in cookies.items()]
每日打卡-07-路徑組裝和獲取環境變量
起止時間: 2020/10/27 08:56 ~ 2020/11/27 23:59
知識點:https://www.cnblogs.com/superhin/p/13880748.html
- 有一個項目結構如下
autotest/
data/
data.csv
testcases/
baidu.py
在baidu.py中如何組裝出項目的根路徑以及data.csv文件的路徑
- 在系統中(Win 環境變量設置, Mac
sudo vim ~/.bash_profile
並source ~/.bash_profile
)手工添加兩個環境變量
USER=admin
PASSWORD=123456
並在baidu.py中讀取出來這兩個變量的值
參考答案
import os
# 1
base_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)
data_file = os.path.join(base_dir, 'data', 'data.csv')
# 2
user = os.getenv('USER')
password = os.getenv('PASSWORD')
每日打卡-08-Python類中的不同方法
起止時間: 2020/10/28 12:23 ~ 2020/11/27 23:59
知識點:https://www.cnblogs.com/superhin/p/13884123.html
- Python類中有哪幾種方法,分別怎么調用?
參考答案
3種,類方法,實例方法,靜態方法,類方法使用類名調用,
實例方法需要創建實例使用實例調用,靜態方法使用類名或者實例都可以調用。
每日打卡-09-使用ini配置文件
起止時間: 2020/10/29 12:23 ~ 2020/11/27 23:59
知識點:https://www.cnblogs.com/superhin/p/13883802.html
- 手工新建一個配置文件config.ini,內容如下
[user]
name=admin
password=123456
is_admin=true
[mysql]
host=10.10.10.10
port=3306
db=apitest
user=root
password=123456
讀取mysql段的配置,並得到一個字典變量
db_conf={'host': '10.10.10.10', 'port': 3306, 'db': 'apitest', 'user': 'root', 'password': '123456'}
注意:port需要是整型
參考答案
from configparser import ConfigParser
conf = ConfigParser()
conf.read('/Users/superhin/項目/示例/data.ini')
db_conf = dict(conf['mysql'])
db_conf['port'] = int(db_conf['port'])
print(db_conf)
每日打卡-10-二分查找
起止時間: 2020/10/30 22:08 ~ 2020/11/27 23:59
知識點:二分查找是一種比較快的查找算法,首先需要序列有序。
思想是先用序列中間數和目標值對比,如果目標值小,則從前半部分(小於中間數)重復此查找,否則從后半部分重復此查找,直到目標值左右兩邊沒有值。
-
- 已知一個列表
l = [0, 9, 8, 1, 10, 2, 5, 3, 11, 6, 13, 100, 24]
l.sort() # 對列表進行排序
此時l=[0, 1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 24, 100]
編寫一個二分查找算法,查找排序后l中8的索引。
參考答案
l = [0, 1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 24, 100]
def bin_find(l, target):
low, high = 0, len(l) - 1 # low, high是兩個游標, 通過不斷地逼近來找到該數字
while low < high:
mid = (high + low) // 2 # 取中間數索引, 注意是 low + high
if target > l[mid]: # 如果目標值比中間數大,移動下游標
print(target, '>', l[mid])
low = mid
elif target < l[mid]: # 如果目標比中間數小,移動上游標
print(target, '<', l[mid])
high = mid
else:
print('找到了, 索引', mid)
return mid
print('未找到')
bin_find(l, 8)
每日打卡-11-高效的集合操作
起止時間: 2020/11/02 09:48 ~ 2020/12/02 23:59
知識點:https://www.cnblogs.com/superhin/p/13913335.html
- 100w條數據,使用列表和集合哪個查詢效率比較高?為什么?
- 為什么Redis查詢很快?
- 在A-B測試中,假設A桶返回的數據為
{'code': 0, 'msg': 'success', 'data': [{'productId': 123, 'productName': 'lv包'},{'productId': 321, 'productName': 'prada包'},{'productId': 542, 'productName': 'gucci包'},{'productId': 412, 'productName': 'fendi包'},{'productId': 631, 'productName': 'ysl包'},{'productId': 221, 'productName': 'mcm包'},{'productId': 541, 'productName': 'penko包'}]}
B桶數據為
{'code': 0, 'msg': 'success', 'data': [{'productId': 123, 'productName': 'lv包'},{'productId': 321, 'productName': 'proda包'},{'productId': 541, 'productName': 'gucci包'},{'productId': 412, 'productName': 'fendi包'},{'productId': 631, 'productName': 'ysl包'},{'productId': 121, 'productName': 'mcm包'},{'productId': 541, 'productName': 'penko包'}]}
利用集合操作快速找出A桶和B桶的數據差異。
參考答案
- 集合查詢效率高,因為集合是基於哈希算法的,無論數據量多少,查詢只需要一次操作。
- Redis是存儲與內存中的基於哈希算法的key-value鍵值對,無論數據量多少,單次查詢只需要一次操作。
- 代碼如下
res_a = {'code': 0, 'msg': 'success', 'data': [{'productId': 123, 'productName': 'lv包'}, {'productId': 321, 'productName': 'prada包'}, {'productId': 542, 'productName': 'gucci包'}, {
'productId': 412, 'productName': 'fendi包'}, {'productId': 631, 'productName': 'ysl包'}, {'productId': 221, 'productName': 'mcm包'}, {'productId': 541, 'productName': 'penko包'}]}
res_b = {'code': 0, 'msg': 'success', 'data': [{'productId': 123, 'productName': 'lv包'}, {'productId': 321, 'productName': 'proda包'}, {'productId': 541, 'productName': 'gucci包'}, {
'productId': 412, 'productName': 'fendi包'}, {'productId': 631, 'productName': 'ysl包'}, {'productId': 121, 'productName': 'mcm包'}, {'productId': 541, 'productName': 'penko包'}]}
# 將 res_a['data']中, 每一項字典,如{'productId': 123, 'productName': 'lv包'},改為可哈希的元祖(123, 'lv包')格式
data_a = [(item['productId'], item['productName']) for item in res_a['data']]
data_b = [(item['productId'], item['productName']) for item in res_b['data']]
data_a = set(data_a) # 轉為集合
data_b = set(data_b)
print('A桶有-B桶無', data_a - data_b)
print('B桶有-A桶無', data_b - data_a)
打印結果
A桶有-B桶無 {(321, 'prada包'), (221, 'mcm包'), (542, 'gucci包')}
B桶有-A桶無 {(541, 'gucci包'), (121, 'mcm包'), (321, 'proda包')}
每日打開-12-使用Yaml文件
起止時間: 2020/11/03 09:18 ~ 2020/12/03 23:59
JSON是一種非常流行的數據格式,支持多種數據類型並支持嵌套,並可以快速轉為Python中的字典或列表類型。
然而由於JSON格式嚴格、不支持注釋。因此有了更簡潔強大的YAML格式,YAML兼容JSON格式,表述起來非常簡潔易用,因此成為很多開發者歡迎。
知識點:<https://www.cnblogs.com/superhin/p/11503756.html?
安裝方式: pip install pyyaml
假設我們想將一個用例描述為如下,一個用例,有用例名稱,並包含多個步驟,每個步驟都包含command操作、target目標、value值三個屬性,command支持open/click/type三種操作,taget和value允許為空,其中
target支持'id=,' 'name=', 'class name'='', 'css selector=', ....等八種。
已百度搜索為例,我們可以用字典描述為
{
'case_name': '百度搜索',
'steps': [
{'command': 'open', 'target': 'https://www.baidu.com/', 'value': ''},
{'command': 'type', 'target': 'id=kw', 'value': '雙11'},
{'command': 'click', 'target': 'id=su', 'value': ''}
]
}
- 按yaml格式,手動將數據保存為一個yaml文件,並用Python讀取出來。
- 解析並使用Selenium執行該條用例。
參考答案
- 格式如下
# 文件名: yaml_case.yaml
case_name: 百度搜索
steps:
- command: open
target: https://www.baidu.com/
value:
- command: type
target: id=kw
value: 雙11
- command: click
target: id=su
value:
- 代碼如下
import yaml
from selenium import webdriver
# 定義三個操作函數, 並保持參數簽名統一
def do_open(driver, target, value=None):
print('打開頁面', target)
driver.get(target)
def do_type(driver, target, value):
print(f'在 {target} 輸入 {value}')
elm_loc = target.split('=') # 分割得到定位方式和定位器
driver.find_element(*elm_loc).send_keys(value)
def do_click(driver, target, value=None):
print(f'點擊 {target}')
elm_loc = target.split('=')
driver.find_element(*elm_loc).click()
# 使用字典做動作映射
command_map = {
'open': do_open, # 上面定義的do_open函數
'type': do_type, # 上面定義的do_type函數
'click': do_click, # 上面定義的do_click函數
}
def run_yaml(driver, yaml_file):
# 加載yaml數據,並轉為字典格式
with open(yaml_file, encoding='utf-8') as f:
data = yaml.safe_load(f)
print('執行用例', data.get('case_name'))
for step in data.get('steps', []):
# 讀取每個步驟的 comnand, target, value字段的值
command, target, value = step.get('command'), step.get('target'), step.get('value')
# 獲取對應的操作函數
func = command_map.get(command)
# 執行函數
func(driver, target, value)
# 測試一下
if __name__ == "__main__":
driver = webdriver.Chrome()
yaml_file = '/Users/superhin/項目/示例/yaml_case.yaml'
run_yaml(driver, yaml_file)
每日打卡-13-使用日志
起止時間: 2020/11/04 11:32 ~ 2020/12/04 23:59
知識點:https://www.cnblogs.com/superhin/p/13924876.html
- 使用Selenium打開https://www.zhipin.com/,搜索框輸入 "測試工程師",並按回車,城市點擊 "北京",
定位出首頁所有的職位鏈接。
要求每一步操作前輸出INFO級的日志,同時輸出到屏幕和文件run.log中,最后運行后,日志輸出如下。
2020/11/04 11:31:49 [INFO] 啟動瀏覽器
2020/11/04 11:31:51 [INFO] 打開BOSS直聘
2020/11/04 11:31:53 [INFO] 搜索框輸入測試工程師並回車
2020/11/04 11:31:54 [INFO] 點擊北京
2020/11/04 11:31:54 [INFO] 定位所有標題連接
2020/11/04 11:31:54 [INFO] 標題個數: 30
2020/11/04 11:31:54 [INFO] 退出瀏覽器
注意日志格式和不要輸出Selenium自帶的DEBUG日志。
參考答案
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import logging
cli_handler = logging.StreamHandler() # 輸出到屏幕的日志處理器
file_handler = logging.FileHandler(filename='run.log', mode='a', encoding='utf-8') # 輸出到文件的日志處理器
logging.basicConfig(level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
datefmt='%Y/%m/%d %H:%M:%S',
handlers=[cli_handler, file_handler] # 添加兩個日志處理器
)
logging.info('啟動瀏覽器')
dr = webdriver.Chrome()
dr.implicitly_wait(10)
logging.info('打開BOSS直聘')
dr.get('https://www.zhipin.com/')
logging.info('搜索框輸入測試工程師並回車')
dr.find_element('name', 'query').send_keys('測試工程師'+Keys.ENTER)
logging.info('點擊北京')
dr.find_element('link text', '北京').click()
logging.info('定位所有標題連接')
links = dr.find_elements('css selector', 'span.job-name>a')
logging.info(f'標題個數: {len(links)}')
logging.info('退出瀏覽器')
dr.quit()
每日打卡-14-使用Cookies繞過登錄
起止時間: 2020/11/05 09:06 ~ 2020/12/04 23:59
知識點:https://www.cnblogs.com/superhin/p/11481803.html
- 使用接口請求獲取cookies,直接繞過商之翼系統的登錄,直接訪問,添加分類鏈接
http://39.104.14.232/newecshop/admin/category.php?act=add,然后添加一個名為'某某某的分類'的商品分類
參考答案
import requests
from selenium import webdriver
from time import sleep
base_url = 'http://****'
username = '****'
password = '****'
login_url = base_url + '/newecshop/admin/privilege.php' # 登錄接口地址
admin_url = base_url + '/newecshop/admin' # 后台登錄頁地址
add_category_url = base_url + '/newecshop/admin/category.php?act=add' # 添加分類頁面地址
# 獲取cookie
data = dict(username=username,password=password, act='signin')
res = requests.post(login_url, data=data, allow_redirects=False)
esscp_id = res.cookies.get('ECSCP_ID')
cookie = dict(name='ECSCP_ID',value=esscp_id)
print('cookie' ,cookie)
# 通過添加cookie繞過登錄
driver = webdriver.Chrome()
driver.get(admin_url)
driver.add_cookie(cookie)
driver.get(add_category_url) # 需要打開兩次
driver.find_element('name', 'cat_name').send_keys('hzc_分類1') # 輸入分類名稱
driver.find_element('css selector', 'input[type=submit]').click() # 點擊確定
sleep(3)
driver.quit()
每日打卡-15-使用Docker及Zalenium
起止時間: 2020/11/06 09:06 ~ 2020/12/04 23:59
知識點:https://www.cnblogs.com/superhin/p/13857584.html
- 安裝Docker並安裝Zalenium,使用Zalenium提供的Selenium Grid服務運行一條商之翼登錄的用例,並查看錄像。
請提交代碼及截圖。
實踐題目-無參考答案
每日打卡16-理解Python中的裝飾器
起止時間: 2020/11/09 11:37 ~ 2020/12/09 23:59
知識點:https://www.cnblogs.com/superhin/p/13947725.html
以下三個練習完成一項即可提交。
- 編寫一個基礎裝飾器info(func),在運行函數前,打印一條信息
print('調用->{func.name}') # func是函數對象func.__name__可以獲取函數名稱
並裝飾以下函數。
@info
def add(a, b):
return a + b
add(1,2)
- 編寫一個可以打印函數參數的裝飾器info(func),在函數運行前,打印一條信息
print('調用->add 參數: {args} {kwargs}')
- 編輯一個帶參數的裝飾器custom_info(verbosity=1):
verbosity默認為1時,在函數運行前打印
print('調用->{func.__name__}')
當verbosity為2時,在函數運行前打印
print('調用->{func.__name__} 參數: {args} {kwargs}') # args kwargs 代表被裝飾的函數參數
當verbosity>2時,在函數運行前打印
print('調用->{func.__name__} 參數: {args} {kwargs}')
在函數運行后打印
print('調用->{func.__name__} 結果: {result}') # result代表函數結果
並裝飾函數
@custom_info(3)
def add(a, b):
return a + b
add(1,2)
查看結果。
參考答案
- 代碼如下
def info(func):
print(f'調用->{func.__name__}')
return func
- 代碼如下
def info(func):
def new_func(*args, **kwargs):
print(f'調用->{func.__name__} 參數: {args} {kwargs}')
return func(*args, **kwargs)
return new_func
- 代碼如下
def custom_info(verbosity=1):
def info(func):
def new_func(*args, **kwargs):
if verbosity == 1:
print(f'調用->{func.__name__}')
elif verbosity > 1:
print(f'調用->{func.__name__} 參數: {args} {kwargs}')
result = func(*args, **kwargs)
if verbosity > 2:
print(f'調用->{func.__name__} 結果: {result}')
return result
return new_func
return info
每日打卡17-練習日期控件操作
起止時間: 2020/11/10 09:17 ~ 2020/12/09 23:59
知識點:https://www.cnblogs.com/superhin/p/13950534.html
- 下載群文件中的,time.zip
鏈接: https://pan.baidu.com/s/1ZA8JsV86S-i4uPD9PRgw8w 密碼: lee4
並解壓,使用瀏覽器打開其中的date.html,並復制出地址。
使用Selenium輸入活動的開始時間和結束時間。
參考答案
from selenium import webdriver
from time import sleep
url = 'file:///Users/superhin/Downloads/Time/date.html'
dr = webdriver.Chrome()
dr.get(url)
js = '''
document.querySelector("input[name='act_start_time']").removeAttribute("readonly");
document.querySelector("input[name='act_stop_time']").removeAttribute("readonly");
'''
dr.execute_script(js)
sleep(.5)
dr.find_element('name', 'act_start_time').send_keys('2020-11-16 00:00')
dr.find_element('name', 'act_stop_time').send_keys('2020-11-27 00:00')
dr.find_element('xpath', '//body').click() # 空白處點擊,以關閉日期彈框
sleep(5)
dr.quit()
每日打卡18-使用JSON文件
起止時間: 2020/11/11 09:17 ~ 2020/12/09 23:59
知識點:https://www.cnblogs.com/superhin/p/11502830.html
- 假設我們用例中需要用到登錄用戶及商品的數據,規划如下
user: # 登錄用戶數據
username: admin
password: 66666
goods: # 商品相關數據
new_goods_001: # 新商品數據001
goods_name: hzc_dell電腦
cat_name: 電腦
shop_price: 3999
轉為字典即
{'goods': {'new_goods_001': {'cat_name': '電腦',
'goods_name': 'hzc_dell電腦',
'shop_price': 3999}},
'user': {'password': '66666', 'username': 'admin'}}
手動將其保存為一個名為data.json的文件,編寫腳本,讀取其中的數據並還原成字典格式,然后提取並打印出其中的用戶名和密碼。
參考答案
data.json內容
{
"goods": {
"new_goods_001": {
"cat_name": "電腦",
"goods_name": "hzc_dell電腦",
"shop_price": 3999
}
},
"user": {
"password": "66666",
"username": "admin"
}
}
讀取腳本
import json
with open('data.json', encoding='utf-8') as f:
data = json.load(f)
print('用戶名', data['user']['username'])
print('密碼', data['user']['password'])
每日打卡19-使用Python發送郵件
起止時間: 2020/11/12 09:35 ~ 2020/12/09 23:59
知識點:https://www.cnblogs.com/superhin/p/13950653.html
- 登錄自己的qq郵箱並開通smtp服務,使用Python腳本發送一封郵件到superhin@126.com,郵件主題中寫上自己的名字。
參考答案
import smtplib # 用於建立smtp連接
from email.mime.text import MIMEText
smtp_server = 'smtp.qq.com'
smtp_user = '***@qq.com'
smtp_password = '****'
def send_email(subject, body, receiver):
msg = MIMEText(body, 'plain', 'utf-8')
msg['From'], msg['To'], msg['Subject'] = smtp_user, receiver, subject
smtp = smtplib.SMTP_SSL(smtp_server)
smtp.login(smtp_user, smtp_password)
smtp.sendmail(smtp_user, "接收郵件地址2", msg.as_string())
smtp.quit()
send_email('某某某', '每日打卡19', 'superhin@126.com')
每日打卡20-為Pytest添加額外參數和配置項
起止時間: 2020/11/13 09:35 ~ 2020/12/09 23:59
知識點:https://www.jianshu.com/p/9a03984612c1
添加自定義選項和配置
- 新建一個空白的pytest項目,使用conftest.py中def pytest_addoption(config) 鈎子方法,為Pytest添加一個命令行參數 --name,添加一個配置項age
- 利用def pytest_terminal_summary(config) 鈎子方法,在最后運行時輸出 參數 name和age的信息。
如,新建pytest.ini
[pytest]
age = 12
運行pytest --name=kevin
,執行最后打印,我是kevin,年齡12
參考答案
目錄中新建conftest.py,內容如下
def pytest_addoption(parser):
"""Pytest初始化時添加選項的方法"""
parser.addoption("--name", help='自定義參數name')
parser.addini('age', help='自定義配置age')
def pytest_terminal_summary(config):
"""Pytest生成報告時的命令行報告運行總結方法"""
name = config.getoption("--name")
age = config.getini('age')
print(f'我是{name},年齡{age}')
運行pytest --name=kevin
后顯示
======================== test session starts ===========================
platform darwin -- Python 3.7.7, pytest-5.4.3, py-1.8.1, pluggy-0.13.1
rootdir: /Users/superhin/項目/示例/pytest_demo, inifile: pytest.ini
plugins: metadata-1.10.0, html-2.1.1
collected 0 items
我是kevin,年齡12
=======================no tests ran in 0.01s ============================
每日打卡21-Python操作Excel
起止時間: 2020/11/16 11:40 ~ 2020/12/16 23:59
知識點:https://www.cnblogs.com/superhin/p/11503933.html
- 新建Excel文件數據格式如下
關鍵詞 結果
Python自動化
Selenium
接口測試
Appium
Postman - 使用Selenium+百度 逐個搜索每一個關鍵詞,成功后在結果列寫入成功。
- (可選)使用Appium+Baidu App 逐個搜索每一個關鍵詞,成功后在結果列寫入成功。
參考答案