• 【pytest】4.fixture介绍和使用


    一、fixture介绍

    fixture是pytest的精髓所在,就像unittest中的setup和teardown一样,如果不学fixture那么使用pytest和使用unittest是没什么区别的(个人理解)。

    1、fixture用途:

    1.做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等;

    2.测试用例的前置条件可以使用fixture实现;

    3.支持经典的xunit fixture ,像unittest使用的setup和teardown;

    4.fixture可以实现unittest不能实现的功能,如unittest中的测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题

    2、fixture介绍:

    初始化测试功能。提供一个固定的基线,在此基线基础上,可以更可靠的进行重复测试。基线可以理解为测试的固定配置,使不同范围的测试都能够获得统一的配置。

    初始化可以设置服务、状态或其他操作环境。在fixture函数中,每个函数的参数通常在test之后被命名为fixture。

    Pytest的fixture相对于传统的xUnit的setup/teardown函数做了显著的改进:

    • fixture有明确的名称,通过在函数、模块、类或整个项目中声明来激活
    • fixture以模块化的方式实现,因为每个fixture名称会触发fixture函数,该fixture函数可以使用其它的fixture函数。
    • fixture不仅可以进行简单的单元测试,也可以进行复杂的功能测试。可以根据配置和组件选项对【fixture和测试】进行参数化,或者跨函数、类、模块或整个测试过程中,重复使用该Fixture函数。
    • 无论使用多少fixture,拆卸逻辑都可以轻松、安全地进行管理,无需手动仔细处理错误,或管理添加清理步骤的顺序。

    此外,pytest依然支持经典的xUnit的样式,你可以根据自己的喜好混合两种样式,逐步从经典样式移动到新样式,甚至可以基于现有的unittest.TestCase或者nose的样式来开发

    二、fixture函数作为用例参数

    1、fixture简单使用

    fixture函数定义:通过@pytest.fixture()装饰器装饰一个函数,这个函数就是一个fixture。fixture函数内部可以实现一些初始化和清理操作。

    pytest运行测试函数时,会查看该测试函数中的参数,然后搜索与这些参数具有相同名称的fixture。一旦pytest找到这些对象,它就会运行这些fixture。

    import pytest
    @pytest.fixture()  # fixture函数定义,不带参数时默认scope="function"
    def login():
        print("输入账号,密码先登录")
    def test_s1(login):
        print("用例1:登录之后其它动作111")
    def test_s2(): 
        print("用例2:不需要登录,操作222")
    
    if __name__ == "__main__":
        pytest.main(["-s", "test_fix.py"])
    

    2、详细介绍

    函数通过使用@pytest.fixture注册成为一个fixture函数,来为测试用例提供一个Fixture函数。对应的测试用例通过在其参数中使用Fixture函数名称来接收Fixture函数。如下:

    import pytest
    # 1、smtp_connection通过使用@pytest.fixture注册成为fixture函数,来为用例提供一个Fixture函数
    @pytest.fixture()  
    def smtp_connection():
    	import smtplib
    	return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
    	
    def test_ehlo(smtp_connection):  # 2、使用Fixture函数名称来接收Fixture函数
    	response, msg = smtp_connection.ehlo()
    	assert response == 250
    	assert 0 # 用于调试
    

    这里,test_ehlo需要smtp_connection这个fixture的返回。pytest会在@pytest.fixture的fixture中查找并调用名为smtp_connection的fixture函数。

    @pytest.fixture没有参数,则默认scope="function",就是用例运行级别为:函数级。

    运行的测试结果如下:

    ================================= FAILURES =================================
    ________________________________ test_ehlo _________________________________
    smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
        def test_ehlo(smtp_connection):
            response,msg = smtp_connection.ehlo()
            assert response == 250
    >       assert 0 # for demo purposes
    E       assert 0
    test_smtpsimple.py:11: AssertionError
    ========================= 1 failed in 0.12 seconds =========================
    

    可看出测试函数test_ehlo调用了smtp_connection,这是由fixture函数创建的smtplib.SMTP()的一个实例。该函数在故意添加的assert 0处失败。步骤如下:

    1. pytest找到以test_作为前缀的测试用例test_ehlo()
    2. test_ehlo()有个名为smtp_connection的入参。而fixture函数中存在一个名为smtp_connection的fixture。所以smtp_connection()被fixture函数调用,用来来创建一个实例。
    3. test_ehlo()被调用,并在最后一行因为断言失败。

    pytest --fixtures test_simplefactory.py:查看可用的fixture(添加-v参数,查看以_开头的fixture)

    3、fixture:通过依赖注入实现

    fixture允许【测试用例函数】轻松的接收和处理【预先定义好的初始化函数】,而不必关心import、setup、cleanup这些细节。

    fixture是依赖注入的的一个极佳的示范,fixture函数是注入器,而测试用例函数是fixture的使用者。

    三、@pytest.mark.usefixtures('fixture')

    1、函数或类前使用@pytest.mark.usefixtures('fixture')装饰器装饰,和使用fixture函数名作为用例参数效果似乎一样,test_fixture.py:

    import pytest
    
    @pytest.fixture()
    def fixtureFunc():
        print('\n fixture->fixtureFunc')
        
    @pytest.mark.usefixtures('fixtureFunc')
    def test_fixture():
        print('in test_fixture')
    
    @pytest.mark.usefixtures('fixtureFunc')
    class TestFixture(object):
        def test_fixture_class(self):
            print('in class with text_fixture_class')
    
    if __name__=='__main__':
        pytest.main(['-v', 'test_fixture.py'])
    

    2、可以同时指定多个fixtures:

    @pytest.mark.usefixtures("cleandir", "anotherfixture")
    def test():...
    

    3、使用mark的通用特性来为测试module指定fixture(注意:这里的变量只能命名为pytestmark,如果命名为其他变量,如foomark不会工作)

    pytestmark = pytest.mark.usefixtures("cleandir")
    

    注意:该标记不会对fixture函数生效,比如下面的代码,不会按照所想的调用my_other_fixture

    @pytest.mark.usefixtures("my_other_fixture")
    @pytest.fixture
    def my_fixture_that_sadly_wont_use_my_other_fixture():...
    

    四、使用autouse参数

    1、简单使用:指定fixture的参数autouse=True,这样范围内的每个测试用例会自动调用fixture(这里fixture的作用范围是函数级别的)

    # test_fixture.py
    import pytest
    @pytest.fixture(autouse=True)
    def fixtureFunc():
        print('\n fixture->fixtureFunc')
    
    def test_fixture():
        print('in test_fixture')
    
    class TestFixture(object):
        def test_fixture_class(self):
            print('in class with text_fixture_class')
    
    if __name__=='__main__':
        pytest.main(['-v', 'test_fixture.py'])
    

    结果如下,可以看到每个测试用例执行前都自动执行了fixture。

     fixture->fixtureFunc
    .in test_fixture
    
     fixture->fixtureFunc
    .in class with text_fixture_class
    

    2、测试用例参数同时接受【普通fixture函数】和【有autouse参数的fixture函数】:

    import pytest
    @pytest.fixture
    def first_entry():return "a"
    
    @pytest.fixture
    def order(first_entry):return []
    
    @pytest.fixture(autouse=True)
    def append_first(order, first_entry):return order.append(first_entry)
    
    def test_string_only(order, first_entry):
        assert order == [first_entry]
    

    测试函数test_string_only(order, first_entry)的执行情况:

    1. 虽然在测试函数里请求了2个fixture函数,但是order拿到的并不是[]first_entry拿到的也并不是"a"
    2. 因为存在一个autouse=True的fixture函数,所以append_first先会被调用执行。
    3. 在执行append_first过程中,又分别请求了order、 first_entry这2和fixture函数。
    4. 接着,append_first对分别拿到的[]"a"进行append处理,最终返回了["a"]
      所以,断言assert order == [first_entry]是成功的。

    五、总结

    @pytest.mark.usefixtures('fixture')使用autouse参数,这两种fixture的使用方式是没有直接使用fixture对象,所以无法使用fixture返回的参数的。因为fixture中返回的数据默认存在fixture名字里面存储,所以只能使用第一种方式才可以调用fixture中的返回值。

    实际工作中尽量少用auto=True这个参数,可能会引发意想不到的结果! 最常用的还是通过传递参数最好!

  • 相关阅读:
    JMX堆栈分析
    Python装饰器示例
    安装指定版本capistrano
    Linux CPU使用率含义及原理
    API gateway 之 kong 安装
    Redis内存分析方法
    Elasticsearch集群内的原理
    Elasticsearch基础
    Python智能检测编码并转码
    (转)rabbitmq的web管理界面无法使用guest用户登录
  • 原文地址:https://www.cnblogs.com/mind18/p/15621642.html
Copyright © 2020-2023  润新知