preamble
In the previous article, we talked about how setup and teardown can be used to add some operations before or after the execution of a use case, but this is a global effect for the entire script.
If you have the following scenario: use case 1 requires login, use case 2 does not require login, and use case 3 requires login. Obviously this can't be done with setup and teardown. fixture allows us to customize the preconditions of our test cases.
The fixture advantage
- Naming is flexible, not limited to setup and teardown.
- Data sharing can be implemented in the configuration so that fixtures can be found automatically without the need for import.
- scope="module" enables multiple .py frontends to be shared across files.
- scope="session" to enable multiple .py cross-files to use one session for multiple use cases
List of fixture parameters
@(scope="function", params=None, autouse=False, ids=None, name=None)
def test():
print("List of parameters for fixture initialization")
parameter list
- scope: can be interpreted as the scope of the fixture, default: function, and class, module, package, session four [common]
- autouse: Default: False, the fixture needs to be called manually by the use case; if it is True, the fixture will be called automatically by all the test cases in the scope.
- name: default: the name of the decorator, it is recommended that fixtures of the same module call each other with a different name.
take note of
Scope of session: the entire test session, i.e., from the start of pytest execution to the end of the test.
How test cases call fixture
- Use the name of the fixture as an input parameter to the test case function
- Test case plus decorator: @(fixture_name)
- fixture set autouse=True
#!/usr/bin/env python # -*- coding: utf-8 -*- """ __title__ = __Time__ = 2020-04-06 15:50 __Author__ = Pineapple Test Notes __Blog__ = /poloyy/ """ import pytest # Call mode one @ def login(): print("Enter your account number and password to log in first.") def test_s1(login): print("Use Case 1: Other actions after login 111") def test_s2(): # Don't pass login print("Use case 2: no login required, operation 222") # Call mode two @ def login2(): print("PLEASE enter your account number and password to log in first.") @("login2", "login") def test_s11(): print("Use Case 11: Other Actions After Login 111") # Calling style three @(autouse=True) def login3(): print("====auto===") # If it doesn't start with test, the decorator won't execute the fixture. @("login2") def loginss(): print(123)
Implementation results
Instantiation order of fixture
- Higher scope fixtures (sessions) are instantiated before lower scope fixtures (functions, classes) [session > package > module > class > function].
- Fixtures with the same scope follow the order in which they are declared in the test function and follow the dependencies between fixtures [fixture_B, which is dependent inside fixture_A, is instantiated first, and then goes to fixture_A for instantiation].
- A fixture that is used automatically (autouse=True) will be instantiated before a fixture that is used explicitly (passing a parameter or decorator)
#!/usr/bin/env python # -*- coding: utf-8 -*- """ __title__ = __Time__ = 2020-04-06 16:14 __Author__ = Pineapple Test Notes __Blog__ = /poloyy/ """ import pytest order = [] @(scope="session") def s1(): ("s1") @(scope="module") def m1(): ("m1") @ def f1(f3, a1): # Instantiate f3, then a1, then f1. ("f1") assert f3 == 123 @ def f3(): ("f3") a = 123 yield a @ def a1(): ("a1") @ def f2(): ("f2") def test_order(f1, m1, f2, s1): # m1, s1 after f1, but will be instantiated first because of the large scope of the scope assert order == ["s1", "m1", "f3", "a1", "f1", "f2"]
Implementation results
Assertion of success
A note about fixtures
Added@
If the fixture also wants to depend on other fixtures, it needs to be passed as a function, not a@()
way, otherwise it will not take effect
@(scope="session") def open(): print("===Open your browser.===") @ # @("open") Not desirable!!!! Not valid!!! def login(open): # method-level preemptive operation setup print(f"Enter account number,Password to log in first{open}")
The previous, in fact, are setup operations, so now let's talk about teardown is how to realize the
Implementing teardown with fixture is not a standalone function, but uses the yield keyword to turn on the teardown operation
#!/usr/bin/env python # -*- coding: utf-8 -*- """ __title__ = __Time__ = 2020-04-06 15:50 __Author__ = Pineapple Test Notes __Blog__ = /poloyy/ """ import pytest @(scope="session") def open(): # Session preemptive operation setup print("===Open your browser.===") test = "Tests whether a variable returns" yield test # Session post operation teardown print("==Close Browser==") @ def login(open): # method-level preemptive operation setup print(f"Enter account number,Password to log in first{open}") name = "==I'm the account number.==" pwd = "==I'm the password.==" age = "==I'm of age.==" # Return variables yield name, pwd, age # method level post operation teardown print("Login successful.") def test_s1(login): print("==use case1==") # Returns a tuple print(login) # Assigned to separate variables name, pwd, age = login print(name, pwd, age) assert "Account number." in name assert "Password." in pwd assert "Age" in age def test_s2(login): print("==use case2==") print(login)
Field Notes
- If the code before the field, i.e., the setup part, has already thrown an exception, the teardown after the field will not be executed.
- If the test case throws an exception, the contents of the teardown after the yield will still be executed normally
Combination of yield+with
# Official examples @(scope="module") def smtp_connection(): with ("", 587, timeout=5) as smtp_connection: yield smtp_connection # provide the fixture value
ought to smtp_connection
The connection will be tested to finish execution after it has been closed because thesmtp_connection
When the object is automatically closed, the with
End of statement.
addfinalizer terminator function
@(scope="module") def test_addfinalizer(request): # Pre-operation setup print("==Open the browser again==") test = "test_addfinalizer" def fin(): # Post-operation teardown print("==Close the browser again==") (fin) # Return the variables of the preceding operation return test def test_anthor(test_addfinalizer): print("==Latest Use Cases==", test_addfinalizer)
caveat
If the code before (), i.e. the setup part, already throws an exception, the teardown content of () will not be executed (similar to yield, I think it's been changed to be consistent in newer versions recently)
Multiple terminating functions can be declared and called
summarize
to this article on the Pytest framework of fixture detailed tutorials on the use of the article is introduced to this, more related to the use of Pytest fixture content, please search for my previous articles or continue to browse the following related articles I hope that you will support me in the future more!