pytest
Mature, full-featured Python testing framework
- Simple and flexible, easy to use
- Support for parameterization
- Skip and Xfail test cases, automatic failure retry, etc
- Support simple unit tests and complex functional tests. It can also be used for Selenium/APPIum automation tests and PyTest + Requests.
- There are many third-party plug-ins and you can customize extensions: Pytest-Allure, Pytest-Xdist (multi-CPU development), etc
- Support Jenkins integration
Pytest User manual
Pytest library installation:
pip install pytest
Test case identification and execution
- Naming requirements for files:
-
- test_*.py
- *_test.py
- Naming requirements for use cases:
-
- The Test* class contains all test_* methods (Test classes cannot have _init_Methods)
- All test_* methods that are not in class
Pytest can implement use cases and methods from the UnitTest framework
Pycharm to use the PyTest framework, you need to specify it as shown in the figure below:
Command line operation mode:
Pytest # Execute the specified file pytest test_material_master.py # Execute the log pytest -vCopy the code
Restore the way you run with the Python interpreter:
The running mode is as follows:
import pytest if __name__ == '__main__': Pytest.main (["test_material_master.py"]) # Run the entire file use case Pytest. Main ([" test_material_master. Py: : TestMaterialMaster: : test_mat_search_by_matCode "]) # run file specified for a use caseCopy the code
Parameterized use
Usage:
Pytest.mark.parametrize (argnames, argvalues) # argNames: parameterized variable; Types: STR (comma separated),list,tuple # argvalues: parameterized values; Type: list, (a tuple)Copy the code
Practical application:
Pytest.mark. parametrize("a, b, expect", get_data(yaml_path, "add"), ids=[" integer ", "decimal "," big integer "]) def test_add(self, a, b, Expect, setup_fixture): """ test positive use case of addition "" result = setup_fixture. Add_func (a, b) assert abs(result-expect) < 0.01Copy the code
Matters needing attention:
Parameter combination (Cartesian product) : Applies when there is only one desired result
import pytest @pytest.mark.parametrize("a", [1, 2, 3]) @pytest.mark.parametrize("b", [4, 5, 6]) def test_add(a, b): Print (" parameter combination a = {}, b = {}". Format (a, b)) print(" parameter combination a = {}, b = {}". PASSED [11%] Parameter combination A = 1, B = 4 PASSED [22%] Parameter combination A = 2, B = 4 PASSED [33%] Parameter combination A = 3, B = 4 PASSED [44%] Parameter combination A = 1, B = 5 PASSED [55%] Parameter combination A = 2, B = 5 PASSED [66%] parameter combination A = 3, B = 5 PASSED [77%] parameter combination A = 1, B = 6 PASSED [88%] Parameter combination A = 2, B = 6 PASSED [100%] Parameter combination A = 3, b = 6Copy the code
skip
Usage scenario: When writing test cases, you can skip a use case that has a bug and cannot be fixed for the moment
Import [email protected] (" There is a bug, Parametrize ("a", [1, 2, 3]) @pytest.mark.parametrize("b", [4, 5, 6]) def test_add(a, b): Print (" a = {}, b = {}". Format (a, b))Copy the code
mark
Usage scenario: Classify and label use cases
Import [email protected] def test_01(): print @pytest.mark.test2 def test_02(): import [email protected] def test_01(): print @pytest.mark.test2 def test_02(): Pytest -s test.py -m test1 # pytest -s test.py -m "not test1" # pytest -s test.py -m "not test1"Copy the code
Front and back
Use case run level
- Module level: start and end of module, globally valid;
setup_module / teardown_module
- Function-level: applies only to function use cases (not to classes);
setup_function / teardown_function
- Class level: run only once before and after a class (used in a class);
setup_class / teardown_class
- Method level: start and end of method (used in classes);
setup_method / teardown_method
- Class, run before and after a method is called;
setup / teardown
The most commonly used* * * *
Fixture: Custom pre-and-post-fixture
Advantages of @pytest.fixture() :
- Naming is flexible, not limited to setup/teardown
- The conftest.py configuration enables data sharing and automatic identification without import
scope="module"
Multiple.py cross-file sharing prefixes can be implemented, with each.py file called oncescope="session"
Multiple.py can be implemented across files using a single session to complete multiple use cases
Import pytest@pytest. fixture(scope="function") # def login_fixture(): Def test_01(login_fixture): # login_fixture (test case 01) def test_02(): Py ::test_01 PASSED in advance [50%] test case 01 test.py::test_02 PASSED [100%] Test case 02Copy the code
Fixture parameters
Scope: scope
- Function: Each test runs, defaulting to scope for function
- Class: All tests for each class are run only once
- Module: All tests for each module are run only once
- Session: Each session runs only once
Autouse: Use with caution
- The default is False
- When True, each test case automatically invokes the fixture without passing in the fixture function name
Arguments are used in fixtures
Fixture functions can be parameterized, in which case they will be called multiple times to execute a set of related tests, the tests that depend on the fixture, and the test functions usually don’t need to know about their rerun
Import pytest@pytest. fixture(params=[" params "," params "]) def myfixture(request): pytest@pytest. fixture(params=[" params "," params "]) def myfixture(request): Print (" execute function in testPytest, %s" % request.param)Copy the code
Arguments are returned in fixtures
Import pytest@pytest. fixture(params=[" params "," params "]) def myfixture(request): pytest@pytest. fixture(params=[" params "," params "]) def myfixture(request): return request.param def test_print_param(myfixture): Print (" execute test_two") print(myfixture) Assert 1==1 # Output PASSED [50%] Execute test_two parameter 1 PASSED [100%] execute test_two parameter 2Copy the code
conftest.py
Application Scenarios:
- Token shared by each interface
- Test case data shared by each interface
- Configuration information shared by each interface
Precautions for use:
- The file name conftest.py is fixed and cannot be changed to another file name
- The conftest.py file must be under the same pakage as the running use case and haveinitThe lead-in file
- Instead of importing through import, pyTest’s use case recognizes it automatically
- The conftest.py file is executed before all test files in the same directory are run
Import pytest@pytest. fixture() def login(): printCopy the code
Post-operation -yield
@pytest.fixture(scope="function") def demo_fix(): print() yield print() def test_1(demo_fix): pytest.fixture(scope="function") def demo_fix(): Def test_2(): def test_3(demo_fix): print() def test_3(demo_fix): print() def test_3(demo_fix): print() def test_3(demo_fix): print()Copy the code
If the code in the test case is abnormal or the assertion fails, it will not affect the code execution after yield in his firmware;
But if there is an error or assertion failure in the pre-yield code in the fixture, which is the equivalent of the setup part, the post-yield code will not execute, and certainly the test case code will not execute
The final function – AddFinalizer
Equivalent to try… Except in the finally
Even if setup fails, AddFinalizer will still perform teardown
@pytest.fixture(scope="session") def login_xadmin_fix(request): s = requests.session() login_xadmin(s) def close_s(): S.close () # Close final cleanup request. Addfinalizer (close_s) return s after the use case is completeCopy the code
Common Parameters
- -v: displays detailed information about the execution of a use case. The file where the use case sits and the name of the use case
- -s: Displays debugging information about a use case. Print information, such as print
- -x: Stops immediately when a use case fails
- -maxfail: stops running when a certain number of use cases fail;
pytest -maxfail=num
- -m: Indicates that the command is running
@ pytest. Mark. The tag name
Test cases for - -k: performs matching test cases. Such as
pytest -k "raises and not delete"
Run all tests that contain RAISES but do not contain DELETES
Introduction to pyTest utility plug-in
Pytest-rerunfailures: Automatically rerun the use case when it fails
Installation method:
pip install pytest-rerunfailures
Copy the code
Usage:
Pytest test_x.py --reruns=n # Number of times to run after a failureCopy the code
You can also specify the number of times to reruns in the script, so that you do not need to use the –reruns parameter when running
@pytest.mark.flaky(reruns=6, reruns_delay=2)
def test_example(self):
print(3)
assert random.choice([True, False])
Copy the code
Pytest-assume: double check
Python’s Assert assertion in PyTest can also write multiple assertions, but if one fails, subsequent assertions will no longer be executed
Pytest-assume, on the other hand, will assume even if the previous assertion fails
Installation method:
pip install pytest-assume
Copy the code
Usage:
def test_simple_assume(x, y):
pytest.assume(x == y)
pytest.assume(True)
pytest.assume(False)
Copy the code
Pytest-xdist: Distributed and concurrent execution
Pytest-xdist allows automated test cases to be distributed, saving automated testing time
Design principles for distributed execution use cases:
- Use cases are independent of each other. There is no dependency between use cases. Use cases can run completely independently.
- Use case execution is not sequential, random order will be normal execution
- Each use case can be run repeatedly without affecting other use cases.
Installation method:
pip install pytest-xdist
Copy the code
Usage:
In the case of parallel execution of multiple cpus, add the -n parameter, num parameter is the number of parallel execution, for example, set num to 3
pytest -n 3
Copy the code
Pytest-ordering: Controls the execution order of use cases
Installation method:
pip install pytest-ordering
Copy the code
Usage:
import pytest
@pytest.mark.run(order=2)
def test_foo():
assert True
@pytest.mark.run(order=1)
def test_bar():
assert True
Copy the code
PS: Try not to make test cases sequential, try not to make test cases dependent!
Hook function customization and extension plug-ins
Pytest calls this hook method after collecting all the test cases. We can customize the function implementation:
- Customize the order of use case execution
- Solve coding problem (Chinese test case name)
- Automatic label adding
It is recommended to write the code for hook functions in the conftest.py file
# conftest.py
from typing import List
def pytest_collection_modifyitems(
session: "Session", config: "Config", items: List["Item"]
) -> None:
for item in items:
item.name = item.name.encode("utf-8").decode("unicode-escape")
item._nodeid = item.nodeid.encode("utf-8").decode("unicode-escape")
Copy the code