Detailed explanation of fixture test fixture of pytest testing framework

Advantages of fixtures
The fixture test fixture of the pytest framework is equivalent to the setup and teardown of the unittest framework, but its functions are relatively more powerful and flexible.

The naming method is flexible and is not limited to the setup and teardown of unittest
. It can realize data sharing. Multiple modules can share prefix and postfix across files.
Multiple modules can be used to complete multiple use cases across files using one session.
Functions that cannot be realized by unittest can be realized, such as Parameters and data cannot be passed between test cases in unittest, but fixtures can solve this problem.
Fixture definition and calling.
Key code: @pytest.fixture(), used to declare that the function is to process prefix and postfix. Test fixture function. Usage is as follows:

<span style="background-color:#282c34"><span style="color:#abb2bf"><span style="color:#61aeee">@pytest.fixture()</span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">my_fixture</span>():</span>	<span style="color:#b18eb1"><em># 记住这个夹具名</em></span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"我的测试夹具"</span>)</span></span>

The test fixture has been defined, so how to call the test case? There are three ways:

Method 1: Pass the fixture name as a parameter to the test case. You can pass multiple fixtures and execute them in order.
Method 2: Decorator: @pytest.mark.usefixtures(fixture_name)
is used on the class, which means that all test cases of this class will Calling this fixture
is used on a use case, which means that only this use case calls this fixture. You
can also use multiple fixtures, executed in order.
If the fixture has a return value, you cannot get the return value using this decorator, and it cannot be passed to the use case. For data, you can only use method one.
Method three: The fixture sets autouse=True to automatically call it. Similarly, when the fixture has a return value, the return value cannot be obtained.

<span style="background-color:#282c34"><span style="color:#abb2bf"><span style="color:#f92672">import</span> pytest
 
 
<span style="color:#61aeee">@pytest.fixture()</span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">my_fixture</span>():</span>	<span style="color:#b18eb1"><em># 记住这个夹具名</em></span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"我的测试夹具"</span>)
 
<span style="color:#b18eb1"><em># 方式一</em></span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_fix1</span>(<span style="color:#a6e22e">my_fixture</span>):</span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"这是测试用例1111"</span>)
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"-------分割线------"</span>)
 
 
<span style="color:#b18eb1"><em># 方式二</em></span>
<span style="color:#b18eb1"><em># 类中应用</em></span>
<span style="color:#61aeee">@pytest.mark.usefixtures(<span style="color:#3388aa">"my_fixture"</span>)</span>
<span style="color:#f92672">class</span> <span style="color:#e6c07b">TestLogin</span>:
 
    <span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_fix2</span>(<span style="color:#a6e22e">self</span>):</span>
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"这是测试用例2222"</span>)
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"-------分割线------"</span>)
 
    <span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_fix3</span>(<span style="color:#a6e22e">self</span>):</span>
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"这是测试用例3333"</span>)
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"-------分割线------"</span>)
 
<span style="color:#b18eb1"><em># 测试用例应用</em></span>
<span style="color:#61aeee">@pytest.mark.usefixtures(<span style="color:#3388aa">"my_fixture"</span>)</span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_fix4</span>():</span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"这是测试用例4444"</span>)
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"-------分割线------"</span>)
 
 
<span style="color:#b18eb1"><em># 方式三</em></span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_fix5</span>():</span>  <span style="color:#b18eb1"><em># 未声明使用测试夹具</em></span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"这是测试用例5555"</span>)
 
 
<span style="color:#f92672">if</span> __name__ == <span style="color:#98c379">"__main__"</span>:
    pytest.main()</span></span>

operation result:

<span style="background-color:#282c34"><span style="color:#abb2bf">Testing started at 23:12 ...
C:\software\python\python.exe ...
 
test.py 我的测试夹具
.这是测试用例1111
-------分割线------
我的测试夹具
.这是测试用例2222
-------分割线------
我的测试夹具
.这是测试用例3333
-------分割线------
我的测试夹具
.这是测试用例4444
-------分割线------
.这是测试用例5555
                                                              [100%]
 
============================== 5 passed in 0.02s ==============================
 
Process finished with exit code 0</span></span>

Why is the test fixture not used in method three? It is because the test fixture has not been set to be automatically called. There is a parameter in the fixture autouse(meaning automatic use). The default is False. When set to True, the use case will automatically call the fixture function. In this way, there is no need to pass parameters every time when writing a use case.

<span style="background-color:#282c34"><span style="color:#abb2bf"><span style="color:#61aeee">@pytest.fixture(autouse=<span style="color:#56b6c2">True</span>)	</span><span style="color:#b18eb1"><em># 设置用例自动调用该fixture</em></span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">my_fixture</span>():</span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"我的测试夹具"</span>)
</span></span>

Fixture scope
There is also a setUpClass and tearDownClass in unittest, which act on classes. They execute the prefix before each test case class is executed, and then execute the postfix after the use case class is executed. The fixture of pytest also has this effect. domain, and is more widely used and more flexible.

​ Key code: @pytest.fixture(scope='scope'), the parameters are as follows:

function: Default scope, each test case is run once
class: Each test class is executed only once
 module: Each module is executed only once
 package: Each python package is executed only once
 session: The entire session is executed only once, that is, running the project The entire process is only executed once
. Priority: session > package > module > class > function. The one with higher priority will be instantiated before the lower fixture.

​ Fixtures in the same scope follow the order of declaration in the function and follow the dependency relationship between fixtures. For example, fixture_B that depends on fixture_A is instantiated first, and then fixture_A is instantiated.

​ When we used the examples of fixtures in the previous examples, we used the default scope. Here is an example of a scenario where the scope is class:

<span style="background-color:#282c34"><span style="color:#abb2bf"><span style="color:#b18eb1"><em># 因为用于演示,因此测试夹具直接写在py文件中</em></span>
<span style="color:#f92672">import</span> pytest
<span style="color:#f92672">from</span> selenium <span style="color:#f92672">import</span> webdriver
 
 
<span style="color:#61aeee">@pytest.fixture(scope=<span style="color:#3388aa">'class'</span>)</span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">my_fixture</span>():</span>
    <span style="color:#98c379">"""前置条件"""</span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"前置条件-启动浏览器"</span>)
    driver = webdriver.Chrome()
    <span style="color:#f92672">yield</span> driver
    driver.quit()
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"后置条件-关闭浏览器"</span>)
 
 
<span style="color:#f92672">class</span> <span style="color:#e6c07b">TestCase</span>:
 
    <span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_case01</span>(<span style="color:#a6e22e">self, my_fixture</span>):</span>    <span style="color:#b18eb1"><em># 这里通过参数传入my_fixture函数,用例执行前会先去执行my_fixture</em></span>
        driver = my_fixture    <span style="color:#b18eb1"><em># my_fixture不需要加括号</em></span>
        driver.get(<span style="color:#98c379">'http://www.baidu.com'</span>)
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">'第一个用例'</span>)
        <span style="color:#f92672">assert</span> <span style="color:#d19a66">1</span> == <span style="color:#d19a66">1</span>
 
    <span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_case02</span>(<span style="color:#a6e22e">self, my_fixture</span>):</span>    <span style="color:#b18eb1"><em># 这里通过参数传入my_fixture函数,用例执行前会先去执行my_fixture</em></span>
        driver = my_fixture    <span style="color:#b18eb1"><em># my_fixture不需要加括号</em></span>
        driver.get(<span style="color:#98c379">'http://www.cnblogs.com/'</span>)
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">'第二个用例'</span>)
        <span style="color:#f92672">assert</span> <span style="color:#d19a66">1</span> == <span style="color:#d19a66">1</span>
 
 
<span style="color:#f92672">if</span> __name__ == <span style="color:#98c379">'__main__'</span>:
    pytest.main([<span style="color:#98c379">'test.py'</span>, <span style="color:#98c379">'-s'</span>])</span></span>

The running results are as follows. As can be seen from the running results, the entire class only opened the browser once.

<span style="background-color:#282c34"><span style="color:#abb2bf">C:\software\python\python.exe D:/learn/test.py
============================= test session starts =============================
platform win32 -- Python 3.7.3, pytest-5.2.2, py-1.8.0, pluggy-0.13.0
rootdir: D:\learn
plugins: html-2.0.0, metadata-1.8.0
collected 2 items
 
test.py 前置条件-启动浏览器
第一个用例
.第二个用例
.后置条件-关闭浏览器
 
 
============================== 2 passed in 9.76s ==============================
 
Process finished with exit code 0
</span></span>

Another parameter of fixture, autouse, was also mentioned earlier. When autouse=True, the use case will automatically execute the test fixture, but the return value of the fixture cannot be obtained. The driver returned in the above example cannot be passed to the use case.

​ If you want the use case to automatically execute the test fixture and hope that the driver and other parameters can be returned to the use case, you can try storing the value in a temporary variable when using the yield keyword in the test fixture to return the value, and then let the use case get the temporary variable. The value in is not given here. The following is a simple example of autouse=True: (the yield keyword will be explained in later chapters)

<span style="background-color:#282c34"><span style="color:#abb2bf"><span style="color:#b18eb1"><em># 因为用于演示,因此测试夹具直接写在py文件中</em></span>
<span style="color:#f92672">import</span> pytest
<span style="color:#f92672">from</span> selenium <span style="color:#f92672">import</span> webdriver
 
 
<span style="color:#61aeee">@pytest.fixture(scope=<span style="color:#3388aa">'class'</span>, autouse=<span style="color:#56b6c2">True</span>)	</span><span style="color:#b18eb1"><em># 所有类自动执行该测试夹具</em></span>
<span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">my_fixture</span>():</span>
    <span style="color:#98c379">"""前置条件"""</span>
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"前置条件-启动浏览器"</span>)
    driver = webdriver.Chrome()
    <span style="color:#f92672">yield</span> driver
    driver.quit()
    <span style="color:#e6c07b">print</span>(<span style="color:#98c379">"后置条件-关闭浏览器"</span>)
 
 
<span style="color:#f92672">class</span> <span style="color:#e6c07b">TestCase</span>:
 
    <span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_case01</span>(<span style="color:#a6e22e">self</span>):</span>	<span style="color:#b18eb1"><em># 不需要传入测试夹具</em></span>
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">'第一个用例'</span>)
        <span style="color:#f92672">assert</span> <span style="color:#d19a66">1</span> == <span style="color:#d19a66">1</span>
 
    <span style="color:#61aeee"><span style="color:#f92672">def</span> <span style="color:#61aeee">test_case02</span>(<span style="color:#a6e22e">self</span>):</span>
        <span style="color:#e6c07b">print</span>(<span style="color:#98c379">'第二个用例'</span>)
        <span style="color:#f92672">assert</span> <span style="color:#d19a66">1</span> == <span style="color:#d19a66">1</span>
 
 
<span style="color:#f92672">if</span> __name__ == <span style="color:#98c379">'__main__'</span>:
    pytest.main([<span style="color:#98c379">'test.py'</span>, <span style="color:#98c379">'-s'</span>])</span></span>

The following are supporting learning materials. For those who are doing [software testing], it should be the most comprehensive and complete preparation warehouse. This warehouse has also accompanied me through the most difficult journey. I hope it can also help you!

Guess you like

Origin blog.csdn.net/2301_76643199/article/details/132760818