zoukankan      html  css  js  c++  java
  • selenium 中装饰器作用

    前面讲到unittest里面setUp可以在每次执行用例前执行,这样有效的减少了代码量,但是有个弊端,比如打开浏览器操作,每次执行用例时候都会重新打开,这样就会浪费很多时间。于是就想是不是可以只打开一次浏览器,执行完用例再关闭呢?这就需要用到装饰器(@classmethod)来解决了。

    一、装饰器

    1.用setUp与setUpClass区别

    setup():每个测试case运行前运行
    teardown():每个测试case运行完后执行
    setUpClass():必须使用@classmethod 装饰器,所有case运行前只运行一次
    tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次

    2.@是修饰符,classmethod是python里的类方法

    二、执行顺序

    1.用类方法写几个简单case,可以对比这篇:Selenium2+python自动化52-unittest执行顺序

    # coding:utf-8
    import unittest
    import time
    class 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 webdriver
    from selenium.webdriver.support import expected_conditions as EC
    import unittest
    class 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 >= 60
    f(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 / num2

    average_1 = dec_1(average_1)
    print(average_1(5, 3)) # => 1.6666666666666667


    # 使用@语法糖的方式
    @dec_1 # (sum = dec(sum))
    def sum_1(num1, num2):
    return num1 + num2

    print(sum_1(5, 3)) # => 8

    # ========================================


    # 能接收任何参数的通用装饰器
    def dec_2(func):
    def wrapper(*arg, **kwargs):

    # --- 附加功能 ---
    print("loging i ...")

    return func(*arg, **kwargs)
    return wrapper


    @dec_2
    def average_2(num1, num2):
    return num1 / num2

    print(average_2(5, 3)) # => loging i ... => 1.6666666666666667


    @dec_2
    def 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()的结果,就在需要的地方调用即可。

    这就是我理解的装饰器,概况来说,就是把需要装饰的函数当做装饰器函数的参数,然后返回一个新函数,在新函数中实现装饰功能。

  • 相关阅读:
    Vue基础简介
    Vue基础简介
    django生命周期请求l流程图
    CSRF与auth模块
    cookie与session django中间件
    Django forms组件与钩子函数
    ajax结合sweetalert实现删除按钮动态效果
    ajax数据交互
    如何绕过CDN找源站ip
    IP地址的另一种形式---一种隐藏IP的方法
  • 原文地址:https://www.cnblogs.com/klb561/p/10085586.html
Copyright © 2011-2022 走看看