In the python language department, there are many available automated testing frameworks, such as unittest+HTMLTestRunner, Nose, etc. in the early days, the Robot Framework is commonly used in recent years. The Robot Framework is the next very general testing framework in Python. Using the mechanism of extension plug-ins can help us realize almost any type of automated testing, Such as interface automation test, App automation test, Web UI automation test, etc.
Today, this article focuses on another general testing framework Pytest in Python language. Although it seems unreasonable to introduce Pytest as the author of Robot Framework, the framework technology is a family, and the framework that can quickly solve practical problems is a good framework. At the beginning of the year, I also published some suggestions on the selection of Robot Framework and Pytest framework: talk about the secret that Robot Framework has been misunderstood for many years. Interested readers can have a look.
One sentence summary: the core idea of Pytest is roughly the same as that of Robot Framework. It can meet the automatic test requirements in different scenarios in the form of plug-in extension.
- Introduction to Pytest
Pytest is a very mature and full-featured Python testing framework. It is similar to Python's own unittest testing framework, but it is simpler and more powerful than the unittest framework.
It provides complete online documents, and has a large number of third-party plug-ins and built-in help, which is suitable for many small or large projects. It is suitable for simple unit testing to complex function testing. You can also execute nose, unittest, and doctest style test cases. Support good integration practices, extended xUnit style setup, and non Python testing. Support the generation of test coverage report and PEP8 compatible coding style.
2. Installation and basic use of pytest
Pytest installation is very simple. You can install it online directly through pip command:
pip install -U pytest
Official Pytest documentation: https://docs.pytest.org/en/latest/
After installation, call the pytest test script mode:
1,py.test:
Pytest provides a command-line tool called directly, namely py Test, latest versions pytest and py Test both command-line tools are available
2,python -m pytest:
Effects and py Like test, this calling method is useful when testing multiple Python versions, such as testing Python 3:
python3 -m pytest [...]
Basic syntax:
usage: py.test [options] [file_or_dir] [file_or_dir] [...]
Introduction to some parameters:
py.test --version View version py.test --fixtures, --funcargs View available fixtures pytest --markers View available markers py.test -h, --help Command line and profile help # Stop after failure py.test -x Stop execution after first failure py.test --maxfail=2 Stop execution after two failures # Debug output py.test -l, --showlocals stay traceback Show local variables in py.test -q, --quiet Silent mode output py.test -v, --verbose Output more detailed information py.test -s Capture output, For example, display print Output of function py.test -r char Displays additional summary information for the specified test type py.test --tb=style Error message output format - long default traceback Information format - native Standard library format - short Shorter format - line One line per error # Run the test for the specified marker pytest -m MARKEXPR # Run matching tests py.test -k stringexpr # Collect and display only available test cases, but do not run test cases py.test --collect-only # Call PDB on failure py.test --pdb
3.Pytest case execution
3.1 use case search rules
If you run pytest without parameters, first find the test case in the path specified by the configuration item testpaths from the configuration file (pytest.ini, tox.ini, setup.cfg). If not, start from the current directory. Otherwise, the command line parameters are used to find directories and files. The search rules are as follows:
Finds the directory starting with test in the specified directory
Recursively traverses a directory unless the directory specifies a different recursion
Find the file name to test_ Start file
Find a class starting with Test (this class cannot have init method)
Find to test_ And test the functions and methods at the beginning
If you want to ignore the lookup path from the default lookup rule, you can add the -- ingore parameter, for example:
pytest --ignore=test_case/xxx.py
3.2 execution selection case
1. Execute all use cases in a single module:
py.test test_demo.py
2. Execute all use cases under the specified path:
py.test somepath
3. Execute use cases in string expressions:
py.test -k stringexpr
4. Run a use case in the specified module, such as test_ demo. Test in py module_ Func test function:
pytest test_demo.py::test_func
5. Run a use case under a class, such as test under TestClass_ Method test method:
pytest test_demo.py::TestClass::test_method
4. Characteristics of pytest fxiture
fixture is a unique function of pytest. It uses pytest fixture ID, defined in front of the function. When writing a test function, you can use the function name as the incoming parameter. Pytest will use the return value of the function as the incoming parameter of the test function in the way of dependency injection.
pytest.fixture(scope='function', params=None, autouse=False, ids=None)
Here, I would like to recommend my learning and exchange place 644956177, the technical Daniel in the group. If you are learning, Xiaobian welcomes you to join. Everyone is a test and Development Party and shares dry goods from time to time, including a copy of the latest 2021 data sorted out by myself.
4.1 as a parameter
fixture can be used as a parameter of other test functions, provided that it must return a value:
@pytest.fixture() def hello(): return "hello" def test_string(hello): assert hello == "hello", "fixture should return hello"
4.2 as setup
fixture can also not return a value, which can be used to run a piece of code before the test method runs:
@pytest.fixture() # Default parameters are called before each test method. def before(): print('before each test') def test_1(before): print('test_1()') @pytest.mark.usefixtures("before") def test_2(): print('test_2()')
This method is similar to setup_method,setup_ Modules are used in the same way. In fact, they are also special fixture s.
In the above example, one test uses pytest mark. Use the fixtures decorator to mark which fixture to use. This usage indicates that the fixture function is applied before starting the test, but its return value is not required.
4.3 scope of fixture
Fixrule can control its scope by setting the scope parameter (it also controls the frequency of calls). If scope = 'module', then the fixture is module level, and this fixture function will only be executed every time the same module is loaded. In this way, some objects that need time to be created can be reused. Fixture provides four scopes to specify the rules for fixture initialization:
Function: execute once before each test function. The default value is
Class: execute once before each class,
Module: each module is executed once before loading
Session: execute once before each session, that is, once for each test
4.4 reverse request
The fixture function can inversely obtain the test function, class or module context in the request by accepting the request object. For example:
@pytest.fixture(scope="module") def smtp(request): import smtplib server = getattr(request.module, "smtpserver", "smtp.qq.com") smtp = smtplib.SMTP(server, 587, timeout=5) yield smtp smtp.close()
Sometimes it is necessary to comprehensively test whether the function of an object under a variety of different conditions meets the expectations. You can set the params parameter of the fixture, and then obtain the set value through request:
class Foo(object): def __init__(self, a, b, c): self.a = a self.b = b self.c = c def echo(self): print(self.a, self.b, self.c) return True @pytest.fixture(params=[["1", "2", "3"], ["x", "y", "z"]]) def foo(request): return Foo(*request.param) def test_foo(foo): assert foo.echo() set up params After parameters, run test Different tests will be generated id,Can pass ids custom id: @pytest.fixture(params=[1, 2, 4, 8], ids=["a", "b", "c", "d"]) def param_a(request): return request.param def test_param_a(param_a): print param_a
4.5 setup/teardown
setup/teardown refers to performing some actions when modules, functions and classes start and end running. For example, to test a database application in a function, you need to connect to the database before the function starts and disconnect from the database after the function runs. setup/teardown is a special fixture, which can be implemented in the following ways:
# Module level def setup_module(module): pass def teardown_module(module): pass # Class level @classmethod def setup_class(cls): pass @classmethod def teardown_class(cls): pass # Method level def setup_method(self, method): pass def teardown_method(self, method): pass # Function level def setup_function(function): pass def teardown_function(function): pass
Sometimes, you want to have a global setup or teardown so that you can do some preparatory work at the beginning of the test, or do some cleaning work after the test. This can be done with hook:
def pytest_sessionstart(session): # setup_stuff def pytest_sessionfinish(session, exitstatus): # teardown_stuff
It can also be implemented in the form of fixture:
@fixture(scope='session', autouse=True) def my_fixture(): # setup_stuff yield # teardown_stuff
4.6 automatic execution
Sometimes some fixtures need to be automatically executed globally, such as the initialization of some global variables, or some global cleaning or initialization functions. At this time, you can set the autouse parameter of the fixture to make the fixture execute automatically. Set to autouse=True to make the function execute by default. The following example will clean up the possible residual files before starting the test, and then set the program directory to this directory:
work_dir = "/c/temp" @pytest.fixture(scope="session", autouse=True) def clean_workdir(): shutil.rmtree(work_dir)
5. Pytest Mark features
The function of marker in pytest is to mark tests to facilitate selective execution of test cases. Pytest provides some built-in markers:
# Skip test @pytest.mark.skip(reason=None) # Skip the test when a condition is met @pytest.mark.skipif(condition) # The test is expected to fail @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False) # Parameterized test function. Add parameters to the test case for the runtime to populate the test # If the parameter name of parameterize conflicts with the fixture name, the fixture will be overwritten @pytest.mark.parametrize(argnames, argvalues) # Execute the given fixtures on the given test # This usage has the same effect as using fixture directly # It's just that you don't need to put the fixture name as a parameter in the method declaration @pytest.mark.usefixtures(fixturename1, fixturename2, ...) # Let the test be executed as soon as possible @pytest.mark.tryfirst # Let the test run as late as possible @pytest.mark.trylast
Where pytest skip and pytest Xfail can realize the function of skipping tests. skip means skipping tests directly, while xfail means there is an expected failure.
In addition to the built-in markers, pytest also supports undefined markers, such as:
@pytest.mark.old_test def test_one(): assert False @pytest.mark.new_test def test_two(): assert False @pytest.mark.windows_only def test_three(): assert False
By using the - m parameter, pytest can selectively execute some tests:
$ pytest test.py -m 'not windows_only'
For a more detailed description of the marker, please refer to the official document: https://docs.pytest.org/en/latest/example/markers.html
- conftest.py file
In a broad sense, conf test Py is a local per directory plug-in where directory specific hooks and fixtures can be defined. py. The test framework looks for conf test in the project it tests Py file, and then look for test options for the entire directory in this file, such as whether to detect and run doctest and which mode should be used to detect test files and functions.
To sum up, conf test Py files have the following functions:
Fixtures: used to provide static test data for test cases, which can be accessed by all tests unless a scope is specified.
Loading plug-ins: used to import external plug-ins or modules: pytest_plugins =“myapp.testsupport.myplugin”
Define hook: used to configure hooks, such as pytest_runtest_setup,pytest_runtest_teardown,pytest_config, etc.
Test root path: if conf test If the PY file is placed in the project root path, pytest will search for sub modules under the project root directory and add them to sys Path, so that all modules in the project can be tested without setting PYTHONPATH to specify the location of project modules.
There can be more than one confitest Py files exist at the same time, and their scope is directory. For example, when the test is very complex, you can create a subdirectory for a specific set of tests and create conf test. In this directory Py file and define a future or hooks. Like the following structure:
test_case ├── conftest.py ├── module1 │ └── conftest.py ├── module2 │ └── conftest.py └── module3 └── conftest.py
7. Pytest plug-in mechanism
Pytest is called a full function testing framework because it can extend the required functions in the form of external plug-ins or custom plug-ins. Here are several common third-party plug-ins:
Pytest xdist: distributed test
Pytest cov: generate test coverage report
pytest-pep8: check whether the code conforms to the PEP8 specification
Pytest flakes: detect code style
Pytest html: generate html report
Pytest randomly: the test sequence is random
Pytest rerunfailures: failed retry
Pytest timeout: timeout test
If you have worked but often feel that there are many difficulties, you feel that you are not good enough to learn in the test, and you want to continue learning. You may be concerned about me if you want to change careers. You can focus on me. [software test dao], you can receive the latest software test, interview with big factories, Python automation, interface, and framework to build learning materials in official account.
If my blog is helpful to you and you like my blog content, please click "like", "comment" and "collect" for three times!