Reputation: 83527
I am currently testing a web app using pytest and Selenium. All pages have "Home" and "Log Out" links, so I have written a test like this:
def test_can_log_out(page):
link = page.find_element_by_partial_link_text('Log Out')
link.click()
assert 'YOU HAVE SUCCESSFULLY LOGGED OFF!' in starting_page.page_source
Now for the page
fixture, I am simulating the login process. I have this broken into several fixtures:
Get the Selenium WebDriver instances
@pytest.fixture()
def browser(request, data, headless):
b = webdriver.Firefox(executable_path=DRIVERS_PATH + '/geckodriver')
yield b
b.quit()
Log in to the web app
@pytest.fixture()
def login(browser):
browser.get('http://example.com/login)
user_name = browser.find_element_by_name('user_name')
user_name.send_keys('codeapprentice')
password = browser.find_element_by_name('password')
password.send_keys('password1234')
submit = browser.find_element_by_name('submit')
submit.click()
return browser
Visit a page
@pytest.fixture()
def page(login):
link = login.find_element_by_partial_link_text('Sub Page A')
link.click()
return login
This works very well and I can test logging out from this page. Now my question is that I have another page which can be visited from "Page A":
@pytest.fixture()
def subpage(page):
button = login.find_element_name('button')
button.click()
return page
Now I want to run the exact same test with this fixture, also. Of course, I can copy/paste and make a few changes:
def test_can_log_out_subpage(subpage):
link = page.find_element_by_partial_link_text('Log Out')
link.click()
assert 'YOU HAVE SUCCESSFULLY LOGGED OFF!' in starting_page.page_source
However, this violates the DRY principle. How can I reuse test_can_log_out()
without this repetition?
Upvotes: 25
Views: 24135
Reputation: 513
Another solution that worked for me was to use classes. It requires a bit more setup than the solutions above, but it can be helpful if you end up having to setup multiple related tests.
You define all of your tests in a single class, and then create a dummy class for each fixture extending that first class:
@pytest.fixture(scope='class')
def fixture1(request):
request.cls.fruit = 'apple'
@pytest.fixture(scope='class')
def fixture2(request):
request.cls.fruit = 'banana'
class ClassOfRelatedTests:
def test_is_banana(self):
assert self.fruit == 'banana'
def test_not_spinach(self):
assert self.fruit != 'spinach'
@pytest.mark.usefixtures("fixture1")
class TestFixture1(ClassOfRelatedTests):
pass
@pytest.mark.usefixtures("fixture2")
class TestFixture2(ClassOfRelatedTests):
pass
Upvotes: 4
Reputation: 2561
Here, you can pass your fixtures
which gives your pages and subpages in test parameters which would be called dynamically as a first step of test. Like below.
When fixtures are on same page where tests are:
testfile.py
import pytest
class TestABC():
@pytest.fixture
def browser(self,request):
print "browser"
@pytest.fixture
def login(self,request,browser):
print "login"
@pytest.fixture
def subpage1(self,request,login):
print "subpage1"
@pytest.fixture
def subpage2(self, request, login):
print "subpage2"
@pytest.fixture
def subpage3(self, request, login):
print "subpage3"
@pytest.mark.parametrize('sub_page',
['subpage1', 'subpage2', 'subpage3'])
def test_can_log_out_subpage(self,sub_page,request):
request.getfixturevalue(sub_page) # with pytest>=3.0.0 use getfixturevalue instead of getfuncargvalue
print "test output of ", sub_page
Output:
browser
login
subpage1
test output of subpage1
browser
login
subpage2
test output of subpage2
browser
login
subpage3
test output of subpage3
When fixtures are at conftest.py
import pytest
@pytest.fixture
def browser(request):
print "browser"
@pytest.fixture
def login(request):
print "login"
@pytest.fixture
def subpage1(request,login):
print "subpage1"
@pytest.fixture
def subpage2(request, login):
print "subpage2"
@pytest.fixture
def subpage3(request, login):
print "subpage3"
testfile.py
import pytest
class TestABC():
@pytest.mark.parametrize('sub_page',
['subpage1', 'subpage2', 'subpage3'])
def test_can_log_out_subpage(self,sub_page,request):
request.getfixturevalue(sub_page) # with pytest>=3.0.0 use getfixturevalue instead of getfuncargvalue
print "test output of ", sub_page
Here, you will also get same output as above.
Hope it would help you.
Upvotes: 24
Reputation: 73
Generally :
@pytest.fixture(scope="function")
def fixture_one():
# set up things
yield
# teardown
@pytest.fixture(scope="function")
def fixture_two():
# do things
@pytest.mark.parametrize('fixture_func', [fixture_one, fixture_two])
def test_things(fixture_func, request):
request.getfixturevalue(fixture_func.__name__)
assert foo == bar
Upvotes: 7
Reputation: 146510
So here is a example I worked out to demonstrate the reuse of fixtures. A fixture can reference another fixture - allowing for a layered approach to writing tests. Please see which one fits the bill for you:
import pytest
@pytest.yield_fixture()
def browser():
print("Launching browser")
b = {}
yield b
print("quitting browser")
@pytest.fixture()
def login(browser):
print("logging in")
@pytest.fixture()
def page(login):
print("on page")
@pytest.fixture()
def subpage(page):
print("on subpage")
@pytest.yield_fixture()
def logout(page):
yield page
print('performing logout using fixtures')
def test_can_log_out(page):
print("logging out using test")
pass
def test_can_log_style2(logout):
print("logging out using fixture")
pass
def test_logout_page2(subpage, logout):
print("test can logout from page 2")
pass
def test_logout_page2_style2(subpage):
print("test can logout from page 2 style2")
test_can_log_out(subpage)
pass
Output of test_can_log_out
Launching browser
logging in
on page
.logging out using test
quitting browser
Output of test_can_log_style2
Launching browser
logging in
on page
.logging out using fixture
performing logout using fixtures
quitting browser
Output of test_logout_page2
Launching browser
logging in
on page
on subpage
.test can logout from page 2
performing logout using fixtures
quitting browser
Output of test_logout_page2_style2
Launching browser
logging in
on page
on subpage
.test can logout from page 2 style2
logging out using test
quitting browser
Upvotes: 2