# 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: ![](https://hackmd.io/_uploads/ByRkZ3YiF.png) ## 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: ![](https://hackmd.io/_uploads/r1-yZ5G2Y.png) ## 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: ![](https://hackmd.io/_uploads/SJa6XcGnt.png) ## 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`