The pytest testing framework essential for Python programming

The most important thing for programming testing is to complete the realization of functions more efficiently.

pytest is a third-party testing framework based on unittest, which is more concise and efficient than unittest, and is perfectly compatible with unittest test code without any modification.

insert image description here

Use of pytest

Use pip install pytest to install the pytest testing framework directly.

pytest sets the function as a fixture through the decorator "@pytest.fixture", so that the corresponding operations can be performed before and after the test starts. In the function, the same function is divided into two parts by yield, which are executed before and after the test respectively, so as to avoid missing the release of resources.

pytest shares data through the conftest.py file, which can be used in other files without importing. And pytest will automatically recognize the conftest.py file without specifying it explicitly. A separate conftest.py file can be set up for subfolders.

The use of the unittest test framework is described in "unittest", an indispensable test framework for Python programming. Here we reimplement the test in the previous article using pytest to observe the difference between unittest and pytest.

We put all the public functions "firmware" into the conftest.py file, and the content of the file is roughly as follows:

DEFAULT_USERNAME = 'test'
DEFAULT_PASSWORD = 'test'

@pytest.fixture
def app():
    db_fd, db_file = tempfile.mkstemp()
    app = create_app()
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+ db_file

print('pytest start')

with app.app_context():
        db.drop_all()
        db.create_all()
        user = User.create(
            name=DEFAULT_USERNAME,
            password=DEFAULT_PASSWORD,
            permission=Permission.ADMINISTRATOR,
            active=True)

yield app
print('pytest stop')
with app.app_context():
        db.session.remove()
        db.drop_all()
    os.close(db_fd)
    os.unlink(db_file)

@pytest.fixture
def clinet(app):
return app.test_client()

@pytest.fixture
def headers(app, clinet):
    rv = clinet.post('/api/v01/user/login',
                        data=json.dumps(dict(user_name='test', password='test')),
                        content_type='application/json')
    data = json.loads(rv.data)
    token = data['token']
    headers = {
    
    "Authorization":"Bearer "+token, 'Content-Type': 'application/json'}

yield headers

pass

The content of the conftest.py file is actually the content of the setUp and setDown functions in unittest. The overall implementation is simpler and clearer.

In the test file, the function marked with the decorator @pytest.fixture can be directly passed into the test function as a parameter with the same name, and the corresponding function can be used in the test function. Also take the test of the two functions of login and add_user as an example to realize the test implementation in the pytest framework:

def test_login(clinet):
    rv = clinet.post('/api/v01/user/login',
                    data=json.dumps(dict(user_name='test', password='test')),
                    content_type='application/json')
    data = json.loads(rv.data)

assert rv.status_code == 200
assert data['status'] == 1
assert data['name'] == 'test'
assert data['token'] isnotNone
assert data['admin'] isnotNone
assert data['expire'] isnotNone

def test_add_user(clinet, headers):

    rv = clinet.post('/api/v01/user',
                    data=json.dumps(dict(user_name='123', password='123', admin=False)),
                    headers=headers)
    data = json.loads(rv.data)
assert rv.status_code == 200
assert data['status'] == 1

In pytest, the method of assert plus expression is used to verify the result, while in unittest, it is completed through assertEqual, assertIn, assertTrue, assertFalse, etc., and more implementations to remember are more complicated.

Use pytest to run the test instance, you can see the following results

================================================================================ test session starts ================================================================================
platform darwin -- Python3.7.5, pytest-5.3.3, py-1.8.1, pluggy-0.13.1
rootdir: ***************
collected 4 items

tests/test_user.py ..                                                                                                                                                         [ 50%]
tests/unittest/test_user_unittest.py ..                                                                                                                                       [100%]

You can see that the test results mark the test progress, and the test cases of unittest are tested synchronously. You can use the -s parameter to display the print output in the test function.

If you use the -s parameter to print the output of the function, you will see that all current firmware "Fixtures" will be executed once at the beginning and completion of each test function. Isn't this a waste of resources? Can each test run Only execute the firmware once, the answer is yes, this requires the scope of the firmware, and setting the scope of the firmware through the decorator @pytest.fixture(scope='session') is the entire testing process. For more information, please see the mind map at the end of the article.

Comparison of unittest and pytest

The firmware "Fixture" implements the pre- and post-functions of the test cases through the fixed functions setUp and tearDown in unittest, and it is for all test cases. In pytest, the function naming method of setting the firmware through decorators is more flexible, and the firmware can be set at the function level, class level, module level, and global level. pytest implements global data sharing with conftest.py as the default configuration.

Assertion implementation In unittest, each judgment method is individually implemented as an assertion function, such as assertEqual, assertIn, assertTrue, assertFalse, etc., which is too cumbersome to use. It is clearer and clearer to directly use the method of assert + expression in pytest.

Parameterized unittest itself does not have the function of parameterization, and pytest can quickly realize parameterization through the decorator @pytest.mark.parametrize.

Guess you like

Origin blog.csdn.net/weixin_44617651/article/details/129851218