每日打卡

每日打卡-01-字符串填空

起止时间: 2020/10/19 09:00 ~ 2020/11/21 23:59
知识点参考 https://www.cnblogs.com/superhin/p/13837611.html

  1. 编写一个函数,输入一个text参数,将函数参数放入字符串 "//*[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

把上述变量渲染到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

  1. 有一个变量
search_ipt_loc = ('id', 'kw')

和函数

def find_element(by, value):
    print(f'通过{by}={value}定位元素')

怎样调用find_element函数将search_ipt_loc中的数据传入?

  1. 有一个字典
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

  1. 设计一个名为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

  1. 假设我们爬取到一批数据
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)

  1. 假设我们有一个列表
    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

  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},
    ]
 }

已知state=0为未开始,1为进行中,2为以结束,使用列表推导式得到当前所有进行中的activityId列表,要求每个activityId转为字符串形式。

  1. 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

  1. 有一个项目结构如下
autotest/
    data/
        data.csv
    testcases/
        baidu.py

在baidu.py中如何组装出项目的根路径以及data.csv文件的路径

  1. 在系统中(Win 环境变量设置, Mac sudo vim ~/.bash_profilesource ~/.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

  1. Python类中有哪几种方法,分别怎么调用?

参考答案

3种,类方法,实例方法,静态方法,类方法使用类名调用,
实例方法需要创建实例使用实例调用,静态方法使用类名或者实例都可以调用。

每日打卡-09-使用ini配置文件

起止时间: 2020/10/29 12:23 ~ 2020/11/27 23:59
知识点:https://www.cnblogs.com/superhin/p/13883802.html

  1. 手工新建一个配置文件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
知识点:二分查找是一种比较快的查找算法,首先需要序列有序。
思想是先用序列中间数和目标值对比,如果目标值小,则从前半部分(小于中间数)重复此查找,否则从后半部分重复此查找,直到目标值左右两边没有值。

    1. 已知一个列表
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

  1. 100w条数据,使用列表和集合哪个查询效率比较高?为什么?
  2. 为什么Redis查询很快?
  3. 在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桶的数据差异。


参考答案

  1. 集合查询效率高,因为集合是基于哈希算法的,无论数据量多少,查询只需要一次操作。
  2. Redis是存储与内存中的基于哈希算法的key-value键值对,无论数据量多少,单次查询只需要一次操作。
  3. 代码如下
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': ''}
]
}

  1. 按yaml格式,手动将数据保存为一个yaml文件,并用Python读取出来。
  2. 解析并使用Selenium执行该条用例。

参考答案

  1. 格式如下
# 文件名: 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:
  1. 代码如下
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

  1. 使用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

  1. 使用接口请求获取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

  1. 安装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
以下三个练习完成一项即可提交。

  1. 编写一个基础装饰器info(func),在运行函数前,打印一条信息
    print('调用->{func.name}') # func是函数对象func.__name__可以获取函数名称
    并装饰以下函数。
@info
def  add(a, b):
    return a + b

add(1,2)
  1. 编写一个可以打印函数参数的装饰器info(func),在函数运行前,打印一条信息
print('调用->add 参数: {args} {kwargs}') 
  1. 编辑一个带参数的装饰器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)

查看结果。


参考答案

  1. 代码如下
def info(func):
    print(f'调用->{func.__name__}')
    return func
  1. 代码如下
def info(func):
    def new_func(*args, **kwargs):
        print(f'调用->{func.__name__} 参数: {args} {kwargs}')
        return func(*args, **kwargs)
    return new_func
  1. 代码如下
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

  1. 下载群文件中的,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

  1. 假设我们用例中需要用到登录用户及商品的数据,规划如下
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

  1. 登录自己的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
添加自定义选项和配置

  1. 新建一个空白的pytest项目,使用conftest.py中def pytest_addoption(config) 钩子方法,为Pytest添加一个命令行参数 --name,添加一个配置项age
  2. 利用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

  1. 新建Excel文件数据格式如下
    关键词 结果
    Python自动化
    Selenium
    接口测试
    Appium
    Postman
  2. 使用Selenium+百度 逐个搜索每一个关键词,成功后在结果列写入成功。
  3. (可选)使用Appium+Baidu App 逐个搜索每一个关键词,成功后在结果列写入成功。

参考答案

原文地址:https://www.cnblogs.com/superhin/p/13894991.html