前面讲到unittest里面setUp可以在每次执行用例前执行,这样有效的减少了代码量,但是有个弊端,比如打开浏览器操作,每次执行用例时候都会重新打开,这样就会浪费很多时间。于是就想是不是可以只打开一次浏览器,执行完用例再关闭呢?这就需要用到装饰器(@classmethod)来解决了。
一、装饰器
1.用setUp与setUpClass区别
setup():每个测试case运行前运行
teardown():每个测试case运行完后执行setUpClass():必须使用@classmethod 装饰器,所有case运行前只运行一次tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次2.@是修饰符,classmethod是python里的类方法
二、执行顺序
1.用类方法写几个简单case,可以对比这篇:
# coding:utf-8
import unittestimport timeclass Test(unittest.TestCase): @classmethod def setUpClass(cls): print "start!"@classmethod
def tearDownClass(cls): time.sleep(1) print "end!" def test01(self): print "执行测试用例01" def test03(self): print "执行测试用例03" def test02(self): print "执行测试用例02" def addtest(self): print "add方法"if __name__ == "__main__": unittest.main()2.从执行结果可以看出,前置和后置在执行用例前只执行了一次。
start!
执行测试用例01执行测试用例02执行测试用例03...end!----------------------------------------------------------------------Ran 3 tests in 1.001s
三、selenium实例
1.可以把打开浏览器操作放到前置setUpClass(cls)里,这样就可以实现打开一次浏览器,执行多个case了
# coding:utf-8
from selenium import webdriverfrom selenium.webdriver.support import expected_conditions as ECimport unittestclass BolgHome(unittest.TestCase): u'''博客首页''' @classmethod def setUpClass(cls): cls.driver = webdriver.Firefox() url = "http://www.cnblogs.com/yoyoketang/" cls.driver.get(url) cls.driver.implicitly_wait(30) @classmethod def tearDownClass(cls): cls.driver.quit() def test_01(self): u'''验证元素存在:博客园''' locator = ("id", "blog_nav_sitehome") text = u"博客园" result = EC.text_to_be_present_in_element(locator, text)(self.driver) self.assertTrue(result) def test_02(self): u'''验证元素存在:首页''' locator = ("id", "blog_nav_myhome") text = u"首页" result = EC.text_to_be_present_in_element(locator, text)(self.driver) self.assertTrue(result)if __name__ == "__main__": unittest.main()
#!/usr/bin/env python
# coding=utf-8__author__ = 'Luzhuo'__date__ = '2017/5/4'# decorator.py 装饰器# 装饰器: 本质是函数, 用于装饰其他函数, 附加一些本身所没有的功能 # 函数就是变量def num(): print("num")num()
num = 1 # 函数就是变量# num() # num的引用被指向1,不能再调用# ========================================
# 高阶函数def func_1(): print("func_1") def func_2(func): # 接收函数变量 func()func_2(func_1) # => func_1
# ========================================
# 闭包def func_3(line): # 闭包: 用于代码封装 和 复用 def comp(value): # 嵌套函数: 函数里再嵌套一个函数 # 函数set_line执行完(生命周期结束), 自由变量(line)仍存活于包裹内 if value >= line: print("{} >= {}".format(value, line)) else: print("{} < {}".format(value, line))return comp
f = func_3(60) # 调用函数A(set_line()),返回函数B(cmp()),这个函数B就叫闭包
f(89) # => 89 >= 60f(59) # => 59 < 60# ========================================
# 装饰器, 在不修改my_average()代码的情况下,为其添加了一些功能(wrapper())def dec_1(func): def wrapper(num1, num2):# --- 附加功能 ---
if num2 == 0: print("num2 值不能为0")return func(num1, num2)
return wrapper # 普通调用方式def average_1(num1, num2): return num1 / num2average_1 = dec_1(average_1)
print(average_1(5, 3)) # => 1.6666666666666667 # 使用@语法糖的方式@dec_1 # (sum = dec(sum))def sum_1(num1, num2): return num1 + num2print(sum_1(5, 3)) # => 8
# ========================================
# 能接收任何参数的通用装饰器def dec_2(func): def wrapper(*arg, **kwargs):# --- 附加功能 ---
print("loging i ...")return func(*arg, **kwargs)
return wrapper @dec_2def average_2(num1, num2): return num1 / num2print(average_2(5, 3)) # => loging i ... => 1.6666666666666667
@dec_2def sum_2(*args): return sum(args)print(sum_2(5, 3, 2, 1)) # => loging i ... => 11
# ========================================
# 能接收不同参数的装饰器def auth(auth_type): # 在外面套一层 def dec_3(func): def wrapper(*arg, **kwargs): # --- 附加功能 --- if auth_type == "admin": print("你是管理员") elif auth_type == "user": print("你是普通用户") else: print("你是外星人吗?")return func(*arg, **kwargs)
return wrapper return dec_3 # 普通调用方式@auth(auth_type="admin")def average_3(*arg): return sum(arg) / len(arg)print(average_3(1, 2, 3, 4, 5)) # => 你是管理员 => 3.0
@auth(auth_type="user")def sum_3(*arg): return sum(arg)print(sum_3(5, 3, 2, 1)) # => 你是普通用户 => 11
# ======================================== # 使用多个装饰器@dec_1@dec_2@auth(auth_type="admin")def average_2(num1, num2): return num1 / num2# 执行顺序dec_1 => dec_2 => auth => average_2
print(average_2(5, 3)) # => loging i ... => 你是管理员 => 1.6666666666666667--------------------- 首先,程序开始从guoguo()执行了,结果它发现该函数前面有个@,就知道该函数被装饰了,那就先去看看装饰了哪些功能吧。然后,该函数就作为参数进入到decorate()中,返回另一个函数test。
最后,test()中就把需要添加给guoguo()的功能写在此处,如果需要guoguo()的结果,就在需要的地方调用即可。
这就是我理解的装饰器,概况来说,就是把需要装饰的函数当做装饰器函数的参数,然后返回一个新函数,在新函数中实现装饰功能。