# 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`