Reputation: 920
I am using pytest with pytest-django and pytest-bdd to test a simple django application. The settings file defines a test sqlite3 database, which is created when the tests are run. My first function creates a model object:
@given("A message exists")
def given_a_message_exists(transactional_db, message_text):
message = message_models.Message(text=message_text)
message.save()
But although I can open and inspect the database using sql-browser, the model is never persisted to the database. I can, in my next function, obtain the message from the django ORM, but the message isn't persisted in the database, and a call to a url route to delete the message returns a 404 with 'Message not found matching the query'.
@when("User visits the delete message page", target_fixture="page")
def user_visits_delete_message_page(transactional_db, browser, message_text):
message = message_models.Message.objects.get(text=message_text)
url = f"{browser.domain}/delete_message/{message.id}/{message.slug}/"
browser.visit(url)
return browser
When I run the site normally, everything works as expected.
Here are the fixtures from my conftest.py...
MESSAGE_TEXT = "Ipsum Lorum Dolum Est"
CREATE_MESSAGE_URL = reverse("django_messages:message_create")
LIST_MESSAGE_URL = reverse("django_messages:message_list")
LINKS_DICT = {
"create_message": f"a[href='{CREATE_MESSAGE_URL}']",
"list_message": f"a[href='{LIST_MESSAGE_URL}']",
}
PAGES_DICT = {
"create_message": CREATE_MESSAGE_URL,
"list_message": LIST_MESSAGE_URL,
}
@pytest.fixture()
def message_text():
return MESSAGE_TEXT
@pytest.fixture()
def browser(sb, live_server, settings):
staging_server = os.environ.get("STAGING_SERVER")
if staging_server:
sb.visit(staging_server)
else:
sb.visit(live_server)
sb.domain = sb.get_domain_url(sb.get_current_url())
settings.EMAIL_PAGE_DOMAIN = sb.domain
sb.pages = PAGES_DICT
sb.links = LINKS_DICT
return sb
Why is the model not persisted to the database when I call message.save()
?
btw, I have tried, transactional_db, and db, along with a whole host of other permutations...
Upvotes: 1
Views: 398
Reputation: 920
It turns out that using the browser fixture causes a problem that I don't fully understand yet. If I pass the browser into a step, and then return it as a target_fixture for later functions to consume then everything works as expected.
[EDIT] I discovered that if I define the browser in a fixture, that I must have referenced that browser fixture before or at the same time as the django object using it, or the browser refers to a different domain. So, in the below, even though the message is created in a fixture (test_message), I must refer to it having referenced the browser. If the function message_exists is not passed 'browser', then the message is not listed on the message_list page.
def message_exists(browser, test_message):
test_message.save()
return test_message
@when("User visits the message list page", target_fixture="page")
def user_visits_messages_page(db, browser):
browser.visit(browser.domain + browser.pages["list_message"])
return browser
@then("The message is listed")
def message_is_listed(message, page):
page.assert_element(f"a[href='/{message.id}/{message.slug}/']")
Upvotes: 1