Comprehensive analysis of pytest for automated testing python

Comprehensive analysis of python pytest:

 

Three ways to run pytest

import pytest

@pytest.mark.finished
def test_add():
   print("测试函数:test_add")


@pytest.mark.finished
def test_subtract():
   print("测试函数:test_subtract")


@pytest.mark.unfinished
def test_no_finish():
   pass
if __name__ == "__main__":
   pytest.main(["-s", "pt_test1.py"])

method one

    pytest.main(["-s", "pt_test1.py"])

way two

  • Create a new pytest in pycharm

     

    image.png

  • Click to run

     

    image.png

way three

  • Execute with command
D:\project\ut>pytest pt_test1.py
======================================================================= test session starts ========================================================================
platform win32 -- Python 3.6.6, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\project\ut
collected 2 items                                                                                                                                                   

pt_test1.py ..                                                                                                                                                [100%]

======================================================================== 2 passed in 0.02s =========================================================================

function for testing

  • ::Make test function
pytest pt_test1.py::test_add
pytest.main(["pt_test1.py::test_add"])

  • -kFuzzy search, test function of fuzzy search add
pytest -k add pt_test1.py
pytest.main(["-s", "pt_test1.py", "-k", "add"])
  • After using pytest.markthe callout, use -mthe parameter
@pytest.mark.finished
def test_add():
    print("测试函数:test_add")

pytest -m finished pt_test1.py
  • A function can be tagged with multiple tags; multiple functions can also be tagged with the same tag to run the logic:
    pytest -m "finished and commit"

skip test

  • pytest.mark.skip
# test_skip.py
@pytest.mark.skip(reason='out-of-date api')
def test_connect():
    pass

pytest tests/test-function/test_skip.py
  • pytest.mark.skipif Specify ignored conditions for test functions
@pytest.mark.skipif(conn.__version__ < '0.2.0',
                    reason='not supported until v0.2.0')
def test_api():
    pass

pytest tests/test-function/test_skip.py

to parameterize

  • Test function for password length
# test_parametrize.py

@pytest.mark.parametrize('passwd',
                      ['123456',
                       'abcdefdfs',
                       'as52345fasdf4'])
def test_passwd_length(passwd):
    assert len(passwd) >= 8

$ pytest tests/test-function/test_parametrize.py
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 3 items

tests\test-function\test_parametrize.py F..                              [100%]

================================== FAILURES ===================================
  • Let's look at another example with multiple parameters, which is used to verify user passwords:
# test_parametrize.py

@pytest.mark.parametrize('user, passwd',
                         [('jack', 'abcdefgh'),
                          ('tom', 'a123456a')])
def test_passwd_md5(user, passwd):
    db = {
        'jack': 'e8dc4081b13434b45189a720b77b6818',
        'tom': '1702a132e769a623c1adb78353fc9503'
    }

    import hashlib

    assert hashlib.md5(passwd.encode()).hexdigest() == db[user]

$ pytest -v tests/test-function/test_parametrize.py::test_passwd_md5_id
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0 -- c:\anaconda3\python.exe
cachedir: .pytest_cache
rootdir: F:\self-repo\learning-pytest, inifile:
collected 2 items

tests/test-function/test_parametrize.py::test_passwd_md5_id[User<Jack>] PASSED [ 50%]
tests/test-function/test_parametrize.py::test_passwd_md5_id[User<Tom>] PASSED [100%]

========================== 2 passed in 0.07 seconds ===========================

firmware

  • Firmware ( Fixture) is some functions, pytestwhich will be loaded and run before (or after) the test function is executed
    - Pytest using pytest.fixture()the definition of firmware, the following is the simplest firmware, only returns the Beijing zip code

@pytest.fixture()
def postcode():
    return '010'


def test_postcode(postcode):
    assert postcode == '010'

preprocessing and postprocessing

  • In many cases, it is necessary to perform preprocessing (such as creating a new database connection) before the test, and clean up (close the database connection) after the test is completed.
  • PytestUse  yield keywords to divide the firmware into two parts. The code before yield is preprocessing and will be executed before the test; the code after yield is postprocessing and will be executed after the test is completed.
# test_db.py

@pytest.fixture()
def db():
    print('Connection successful')

    yield

    print('Connection closed')


def search_user(user_id):
    d = {
        '001': 'xiaoming'
    }
    return d[user_id]


def test_search(db):
    assert search_user('001') == 'xiaoming

============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 1 item

tests\fixture\test_db.py Connection successful
.Connection closed

scope

When defining the firmware,  scope declare the scope through parameters, the options are:

  • function: Function level, each test function will execute the firmware once; the default scope is function
  • class: Class level, each test class is executed once, and all methods can be used;
  • module: Module level, each module is executed once, and functions and methods within the module can be used;
  • session: Session level, a test is executed only once, and all found functions and methods are available.
@pytest.fixture(scope='function')
def func_scope():
    pass


@pytest.fixture(scope='module')
def mod_scope():
    pass


@pytest.fixture(scope='session')
def sess_scope():
    pass


@pytest.fixture(scope='class')
def class_scope():
    pass
  • For class use scope, you need to use pytest.mark.usefixtures (also works for functions and methods):
# test_scope.py

@pytest.mark.usefixtures('class_scope')
class TestClassScope:
    def test_1(self):
        pass

    def test_2(self):
        pass

$ pytest --setup-show tests/fixture/test_scope.py::TestClassScope
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 2 items

tests\fixture\test_scope.py
    SETUP    C class_scope
        tests/fixture/test_scope.py::TestClassScope::()::test_1 (fixtures used: class_scope).
        tests/fixture/test_scope.py::TestClassScope::()::test_2 (fixtures used: class_scope).
    TEARDOWN C class_scope

Pass multiple arguments in pytest using command line

  • configure conftest.py
# conftest.py
import pytest
def pytest_addoption(parser):
    parser.addoption("--input1", action="store", default="default input1")
    parser.addoption("--input2", action="store", default="default input2")

@pytest.fixture
def input1(request):
    return request.config.getoption("--input1")

@pytest.fixture
def input2(request):
    return request.config.getoption("--input2")
  • write test function
# test.py
import pytest

@pytest.mark.unit
def test_print_name(input1, input2):
    print ("Displaying input1: %s" % input1)
    print("Displaying input2: %s" % input2)
  • Excuting an order
>py.test -s test.py --input1 tt --input2 12
================================================= test session starts =================================================
platform win32 -- Python 3.7.0, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
rootdir: pytest, inifile:
collected 1 item

test.py Displaying input1: tt
Displaying input2: 12
.

============================================== 1 passed in 0.04 seconds ====================================

Summary of some other parameters

  • -v, --verbose
    Detailed results
    - -q, --quiet
    simplified result display, simplified console output, it can be seen that the output information is different from the previous one without adding -q no information. In the figure below, there are two .. dots instead of pass results-input the debugging information in our use case, such as the print information of print, etc., we add a sentence print(driver.title) in the use case, let's run our use case again, debug information output-you can output more detailed execution information of the use case, such as the file where the use case is located and the name of the
    use -s
    case
    , -V
    etc.
  • --junit-xml=path
    Output xml file format, used when integrating with jenkins
  • --result-log=path
    Save the final result to a local file

2020-8-21 Added

  • use setup, setup_cass_teardown_class
class TestCase():
    def setup(self):
        print("setup: 每个用例开始前执行")
    def teardown(self):
        print("teardown: 每个用例结束后执行")
    def setup_class(self):
        print("setup_class:所有用例执行之前")
    def teardown_class(self):
        print("teardown_class:所有用例执行之前")
    def setup_method(self):
        print("setup_method: 每个用例开始前执行")
    def teardown_method(self):
        print("teardown_method: 每个用例结束后执行")
    def test_one(self):
        print("正在执行----test_one")
        x = "this"
        assert 'h' in x
    def test_three(self):
        print("正在执行test_two")
        a = "hello"
        b = "hello word"
        assert a in b
    def add(self,a, b):
        print("这是加减法")
        return a + b
if __name__ == '__main__':
    pytest.main(['-s', 'test_fixt_class'])

If you have any questions about learning Python, learning methods, learning routes, and how to learn efficiently, you can consult me ​​at any time, or if you lack systematic learning materials, I have been in this industry for a long time, and I think I am quite experienced. I can help you make constructive suggestions. This is my Python communication qun: 785128166.
 

Guess you like

Origin blog.csdn.net/PythonCS001/article/details/108541383