Try   HackMD

pytest - fixture; Setup and Teardown

1. Setup before and after tests using pytest fixture

https://docs.pytest.org/en/6.2.x/example/simple.html

https://stackoverflow.com/questions/22627659/run-code-before-and-after-each-test-in-py-test

Pass variables via command line using pytest_addoption in conftest.py:

import pytest

def pytest_addoption(parser):
    parser.addoption("--appUrl", action="store", default="https://app.url.com", help="Application url")
    
    parser.addoption("--appUser", action="store", default="admin", help="Application user account")
    parser.addoption("--appPwd", action="store", default="1234", help="Application user password")


@pytest.fixture
def params(request):
    params = {}
    params['appUrl'] = request.config.getoption("--appUrl")
    params['appUser'] = request.config.getoption("--appUser")
    params['appPwd'] = request.config.getoption("--appPwd")
    return params

Wrap setup and teardown steps into corresponding functions:

def close_browser():
    print("close_browser")
    if pytest.browser is not None:
        pytest.browser.quit()


def setup_browser(url):
    print("setup_browser")
    chrome = Chrome(url)  # From another python file which set chrome
    pytest.browser = chrome.get_driver()

Setup browsers before each test, and close browser after each test (no matter test pass or failed):

@pytest.fixture(autouse=True)
def before_and_after_test(params):
    
    setup_browser(params['appUrl'])

    app = AppUI(pytest.browser)
    app.keyinUser(params['appUser'])
    app.keyinPwd(params['appPwd'])
    app.clickLogin()
    
    yield
    
    close_browser()

2. Share variables between tests

https://stackoverflow.com/questions/44441929/how-to-share-global-variables-between-tests

https://docs.pytest.org/en/6.2.x/deprecations.html#pytest-namespace

Set the variable to the pytest variable us pytest_namespace or pytest_configure (depends on the pytest version):

def pytest_namespace():
    return {"driver": None}

Can use it directly in the test case as the following:

pytest.browser = chrome.get_driver()

3. Run test cases by order using pytest-ordering

https://github.com/ftobia/pytest-ordering

For example,

import pytest
import pytest_check as check


@pytest.mark.run(order=1)
def test_first():
    check.is_true(False, "test_first should be true")


@pytest.mark.run(order=3)
def test_third():
    check.is_true(True, "test_third should be true")


@pytest.mark.run(order=2)
def test_second():
    check.is_true(True, "test_second should be true")

4. Run test cases with dependencies using pytest-depends

https://pypi.org/project/pytest-depends/

For example,

import pytest
import pytest_check as check


def test_first():
    check.is_true(True, "test_first should be true")


@pytest.mark.depends(on=['test_second'])
def test_third():
    check.is_true(True, "test_third should be true")


@pytest.mark.depends(on=['test_first'])
def test_second():
    check.is_true(False, "test_second should be true")

The test will skip if the dependent test fails:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

5. Setup and Teardown and the corresponding scope of each method

https://iter01.com/544649.html

Include test cases in class, and load test data from conftest.py

import pytest

def setup_module():
    print("setup_module")

def teardown_module():
    print("teardown_module")

def setup_function():
    print("setup_function")

def teardown_function():
    print("teardown_function")

def setup_method():
    print("setup_method")

def teardown_method():
    print("teardown_method")

def setup():
    print("setup")

def teardown():
    print("teardown")


# test class
class TestClass(object):
    def setup_class(self):
        print("setup_class")

    def teardown_class(self):
        print("teardown_class")

    def test_A(self):
        print("test_A")
        assert "A" == "AA"

    def test_B(self):
        print("test_B")
        assert 1 == 1

    # load test data from conftest
    def test_user(self, params):
        print("test_user")
        defaultUser = "admin"
        assert defaultUser == params['user']

    # load test data from conftest
    def test_pwd(self, params):
        print("test_pwd")
        defaultUser = "123"
        assert defaultUser == params['password']

Command line to run pytest and pass arguments:

pytest tests/testSetupTeardown/testSetupTeardown.py -s --user=user1 --password=123

Result of running test:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

6. Initialize variables for all test cases to use by using setup and teardown

import pytest


class TestClass(object):
    dataMap = {}

    def setup_class(self):
        self.dataMap["A"] = 1
        self.dataMap["B"] = 2
        self.dataMap["C"] = 3

    def teardown_class(self):
        self.dataMap.clear()

    def test_check_first(self):
        print("test_check_first")
        assert self.dataMap["A"] == 1

    def test_check_second(self):
        print("test_check_second")
        assert self.dataMap["B"] == 0

    def test_check_third(self):
        print("test_check_third")
        assert self.dataMap["C"] == 3

Result of running test:

7. Initialize variables for all test cases to use by using setup and teardown, and includes test data from fixtures in conftest.py file

Issue:

ERROR: setup_class() missing 1 required positional argument

Reason:

setup_module and setup_class happen earlier than @pytest.fixture(autouse=True)

Solution 1: (not work)

https://stackoverflow.com/questions/50132703/pytest-fixture-for-a-class-through-self-not-as-method-argument

Solution 2: Initialize variables in fixture function and set the fixture scope to either module or session (class might work too)

@pytest.fixture(scope='module')
def module_data():
    nums = random.sample(range(0, 3), 3)
    print("module_data: " + str(nums))
    return nums


@pytest.fixture(scope='session')
def session_data():
    nums = random.sample(range(4, 7), 3)
    print("session_data: " + str(nums))
    return nums


@pytest.fixture(scope='function')
def function_data():
    nums = random.sample(range(8, 11), 3)
    print("function_data: " + str(nums))
    return nums


def test_first_num(module_data, session_data, function_data):
    # assert module_data[0] == 0
    check.equal(module_data[0], 0)
    check.equal(session_data[0], 4)
    check.equal(function_data[0], 8)

8. fixture use another fixture

https://stackoverflow.com/questions/56402600/pytest-calling-a-fixture-from-another-fixture
For example, a fixture uses another fixture from conftest.py file:

tags: python pytest test automation software test tdd unit test