1. Introduction
This article is about the hottest third-party unit testing framework in the Python world: pytest.
It has the following main features:
- assert Output detailed information when the assertion fails (no need to remember
self.assert*
the name ) - Automatic discovery of test modules and functions
- Modular fixtures to manage various test resources
unittest
Fully compatible with ,nose
basically compatible with- Very rich plug-in system, with more than 315 third-party plug-ins, the community is prosperous
Like the previous introduction unittest
and nose
, we will introduce the features pytest
of .
2. Use case writing
nose
Similarly , pytest
test cases in the form of functions and test classes are supported. The biggest difference is that you can use assert
the statement to make assertions without worrying about the lack of detailed context information it will generate in ornose
.unittest
For example, in the following test example, the assertion test_upper
in failed:
import pytest
def test_upper():
assert 'foo'.upper() == 'FOO1'
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
with pytest.raises(TypeError):
x + []
And when using pytest
to execute a test case, it will output detailed (and multi-colored) context information:
=================================== test session starts ===================================
platform darwin -- Python 3.7.1, pytest-4.0.1, py-1.7.0, pluggy-0.8.0
rootdir: /Users/prodesire/projects/tests, inifile:
plugins: cov-2.6.0
collected 3 items
test.py F.. [100%]
======================================== FAILURES =========================================
_______________________________________ test_upper ________________________________________
def test_upper():
> assert 'foo'.upper() == 'FOO1'
E AssertionError: assert 'FOO' == 'FOO1'
E - FOO
E + FOO1
E ? +
test.py:4: AssertionError
=========================== 1 failed, 2 passed in 0.08 seconds ============================
It is not difficult to see that pytest
both the test code context and the value of the measured variable are output. Compared with nose
and unittest
, pytest
allow users to write test cases in a simpler way, and get a richer and more friendly test result.
3. Use case discovery and execution
unittest
nose
Both supported use case discovery and execution capabilities pytest
are supported. pytest
Automatic (recursive) discovery of supported use cases:
- By default,
test_*.py
all*_test.py
test case files that match or in the current directory, test functionstest
starting or test methods starting withTest
in test classes startingtest
with - use
pytest
command nose2
Same idea as , by specifying specific parameters in the configuration file, the name patterns of use case files, classes and functions can be configured (fuzzy matching)
pytest
Executing specific use cases is also supported:
- Specify test file path
pytest /path/to/test/file.py
- Specify test class
pytest /path/to/test/file.py:TestCase
- specify test method
pytest another.test::TestClass::test_method
- specify test function
pytest /path/to/test/file.py:test_function
Fourth, the test fixture (Fixtures)
pytest
The style of the test fixtureunittest
is very different from that of , , nose
and . nose2
It can not only setUp
realize tearDown
the test pre-test and cleanup logic of and , but also has many other powerful functions.
4.1 Declaration and use
pytest
A test fixture in is more like a test resource, you just define a fixture and then use it directly in a use case. Thanks pytest
to the dependency injection mechanism of , you don't need from xx import xx
to display the import through the form, you only need to specify the parameters with the same name in the parameters of the test function, for example:
import pytest
@pytest.fixture
def smtp_connection():
import smtplib
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
In the above example, a test fixture is defined smtp_connection
, and a parameter with the same name is defined in the test function test_ehlo
signature , then pytest
the framework will automatically inject the variable.
4.2 Sharing
pytest
In , the same test fixture can be shared by multiple test cases in multiple test files. Just define conftest.py
the file , and write the definition of test fixtures in this file, then all test cases of all modules (Module) in the package can use conftest.py
the test fixtures defined in .
For example, if a test fixture is test_1/conftest.py
defined , then test_a.py
and test_b.py
can use the test fixture; but test_c.py
cannot.
`-- test_1
| |-- conftest.py
| `-- test_a.py
| `-- test_b.py
`-- test_2
`-- test_c.py
4.3 Validity levels
unittest
nose
Both support test pre- and cleanup levels: test method, test class, and test module.
pytest
The test fixtures also support various validation levels and are more abundant. Set by specifying scope
the parameter :
- function —— function level, that is, before calling each test function, the fixture will be regenerated
- class —— class level, before calling each test class, the fixture will be regenerated
- module —— module level, before loading each test module, the fixture will be regenerated
- package —— package level, before loading each package, the fixture will be regenerated
- session —— session level, before running all use cases, only generate fixture once
When we specify the effective level as the module level, the example is as follows:
import pytest
import smtplib
@pytest.fixture(scope="module")
def smtp_connection():
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
4.4 Test Prep and Cleanup
pytest
The test fixture can also implement test pre-test and clean-up. The two logics are split by yield
the statement , and the writing method becomes very simple, such as:
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp_connection():
smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
yield smtp_connection # provide the fixture value
print("teardown smtp")
smtp_connection.close()
In the above example, yield smtp_connection
the previous statement is equivalent to the test pre-test, and the prepared test resource yield
is returned by smtp_connection
; while the latter statement will be after the end of the use case execution (to be exact, the end of the statement cycle of the effective level of the test fixture) Execution, equivalent to test cleanup.
If the procedure for generating test resources (as in the example smtp_connection
) supports with
statements , it can also be written in a simpler form:
@pytest.fixture(scope="module")
def smtp_connection():
with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:
yield smtp_connection # provide the fixture value
pytest
In addition to the functions introduced in this article, the test fixture also has more advanced gameplay such as parameterized fixtures, factory fixtures, and using fixtures in fixtures.
5. Skipped tests and expected failures
pytest
In addition to supporting unittest
and nosetest
methods of skipping tests and predicting failures, it also provides corresponding methods pytest.mark
in :
- Skip tests directly via skip decorator or pytest.skip function
- Conditionally skip tests via skipif
- Expected test failure via xfail
Examples are as follows:
@pytest.mark.skip(reason="no way of currently testing this")
def test_mark_skip():
...
def test_skip():
if not valid_config():
pytest.skip("unsupported configuration")
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_mark_skip_if():
...
@pytest.mark.xfail
def test_mark_xfail():
...
6. Sub-test/parameterized test
pytest
In addition to the support unittest
in TestCase.subTest
, it also supports a more flexible way of writing subtests, that is 参数化测试
, through pytest.mark.parametrize
decorators .
In the following example, define a test_eval
test function and pytest.mark.parametrize
specify 3 sets of parameters through the decorator, then 3 subtests will be generated:
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
assert eval(test_input) == expected
In the example, the last set of parameters is deliberately allowed to cause failure, and you can see rich test result output when you run the test case:
========================================= test session starts =========================================
platform darwin -- Python 3.7.1, pytest-4.0.1, py-1.7.0, pluggy-0.8.0
rootdir: /Users/prodesire/projects/tests, inifile:
plugins: cov-2.6.0
collected 3 items
test.py ..F [100%]
============================================== FAILURES ===============================================
__________________________________________ test_eval[6*9-42] __________________________________________
test_input = '6*9', expected = 42
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
> assert eval(test_input) == expected
E AssertionError: assert 54 == 42
E + where 54 = eval('6*9')
test.py:6: AssertionError
================================= 1 failed, 2 passed in 0.09 seconds ==================================
If the parameters are replaced pytest.param
, we can also have higher-level gameplay, such as knowing that the last set of parameters failed, so mark it as xfail:
@pytest.mark.parametrize(
"test_input,expected",
[("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],
)
def test_eval(test_input, expected):
assert eval(test_input) == expected
If the values of multiple parameters of the test function want to be arranged and combined with each other, we can write like this:
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
pass
In the above example x=0/y=2
, , x=1/y=2
, x=0/y=3
and x=1/y=3
are brought into the test function respectively, and are executed as four test cases.
7. Test result output
pytest
The test result output unittest
of nose
is more abundant than that of and , and its advantages are:
- Highlight output, pass or fail will be distinguished by different colors
- Richer context information, automatically output code context and variable information
- Test progress display
- Test result output layout is more friendly and easy to read
If you exchange experience in software testing, interface testing, automated testing, and interviews. If you are interested, you can add software testing communication: 1085991341, and there will be technical exchanges with colleagues.
Eight, plug-in system
pytest
The plug-ins are very rich, and plug-and-play, as users do not need to write additional code.
In addition, thanks to the pytest
good architecture design and hook mechanism, its plug-in writing has also become easy to use.
Nine. Summary
This concludes three introductions to the Python testing framework. After writing so much, the judges are probably tired of reading. We might as well list a horizontal comparison table to summarize the similarities and differences of these unit test frameworks:
If you don't want to install or disallow third-party libraries, then unittest
is the best and only option. On the contrary, pytest
it is undoubtedly the best choice, and many Python open source projects use it pytest
as a unit testing framework.
The above content is the entire content of this article. I hope the above content is helpful to you. Friends who have been helped are welcome to like and comment.
END meager strength
Finally, I would like to thank everyone who has read my article carefully. Looking at the fans’ growth and attention all the way, there is always a need for reciprocity. Although it is not a very valuable thing, you can take it away if you need it:
These materials should be the most comprehensive and complete preparation warehouse for [software testing] friends. This warehouse has also accompanied tens of thousands of test engineers through the most difficult journey, and I hope it can help you too!
加入我的软件测试交流群:110685036免费获取~(同行大佬一起学术交流,每晚都有大佬直播分享技术知识点)
Software testing interview applet
The software test question bank maxed out by millions of people! ! ! Who is who knows! ! ! The most comprehensive quiz mini program on the whole network, you can use your mobile phone to do the quizzes, on the subway or on the bus, roll it up!
The following interview question sections are covered:
1. Basic theory of software testing, 2. web, app, interface function testing, 3. network, 4. database, 5. linux
6. web, app, interface automation, 7. performance testing, 8. programming basics, 9. hr interview questions, 10. open test questions, 11. security testing, 12. computer basics
method of obtaining: