Skip to content

Commit

Permalink
Merge pull request #146 from /issues/142
Browse files Browse the repository at this point in the history
Issues/142 - Acceptance test time improvements
  • Loading branch information
jantman authored Nov 3, 2017
2 parents 12df0e2 + f3aea66 commit 7f5edba
Show file tree
Hide file tree
Showing 19 changed files with 749 additions and 353 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Unreleased Changes
and formatting used in the user interface and logs.
* `PR #141 <https://github.com/jantman/biweeklybudget/pull/141>`_ - Switch acceptance tests from PhantomJS to headless Chrome.
* Switch docs build screenshot script to use headless Chrome instead of PhantomJS.
* `Issue #142 <https://github.com/jantman/biweeklybudget/issues/142>`_ - Speed up acceptance tests. The acceptance tests recently crossed the 20-minute barrier, which is unacceptable. This makes some improvements to the tests, mainly around combining classes that can be combined and also using mysql/mysqldump to refresh the DB, instead of refreshing and recreating via the ORM. That offers a approximately 50-90% speed improvement for each of the 43 refreshes. Unfortunately, it seems that the majority of time is taken up by pytest-selenium; see Issue 142 for further information.

0.5.0 (2017-10-28)
------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@


@pytest.mark.acceptance
@pytest.mark.usefixtures('refreshdb', 'testflask')
class TestAccountsNavigation(AcceptanceHelper):

@pytest.fixture(autouse=True)
def get_page(self, base_url, selenium, testflask, refreshdb): # noqa
def get_page(self, base_url, selenium):
self.baseurl = base_url
self.get(selenium, base_url + '/accounts')

Expand All @@ -67,10 +68,11 @@ def test_notifications(self, selenium):


@pytest.mark.acceptance
@pytest.mark.usefixtures('refreshdb', 'testflask')
class TestAccountsMainPage(AcceptanceHelper):

@pytest.fixture(autouse=True)
def get_page(self, base_url, selenium, testflask, refreshdb): # noqa
def get_page(self, base_url, selenium):
self.baseurl = base_url
self.get(selenium, base_url + '/accounts')

Expand Down Expand Up @@ -153,6 +155,7 @@ def test_investment_table(self, selenium):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
@pytest.mark.incremental
class TestAccountModal(AcceptanceHelper):

def test_10_verify_db(self, testdb):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
from pytz import UTC

from biweeklybudget.tests.acceptance_helpers import AcceptanceHelper
import biweeklybudget.models.base # noqa
from biweeklybudget.tests.conftest import engine
from biweeklybudget.tests.sqlhelpers import restore_mysqldump
from biweeklybudget.models.account import Account, AcctType
from biweeklybudget.models.budget_model import Budget
from biweeklybudget.models.ofx_transaction import OFXTransaction
Expand All @@ -54,10 +54,11 @@


@pytest.mark.acceptance
@pytest.mark.usefixtures('refreshdb', 'testflask')
class TestBaseTemplateNavigation(AcceptanceHelper):

@pytest.fixture(autouse=True)
def get_page(self, base_url, selenium, testflask, refreshdb): # noqa
def get_page(self, base_url, selenium):
self.baseurl = base_url
self.get(selenium, base_url)

Expand Down Expand Up @@ -99,10 +100,11 @@ def test_nav_links(self, selenium):


@pytest.mark.acceptance
@pytest.mark.usefixtures('refreshdb', 'testflask')
class TestBaseTemplateNotifications(AcceptanceHelper):

@pytest.fixture(autouse=True)
def get_page(self, base_url, selenium, testflask, refreshdb): # noqa
def get_page(self, base_url, selenium):
self.baseurl = base_url
self.get(selenium, base_url)

Expand All @@ -123,13 +125,12 @@ def test_stale_accounts(self, selenium):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb')
@pytest.mark.incremental
class TestBaseTmplUnreconciledNotification(AcceptanceHelper):

def test_00_clean_db(self, testdb):
# clean the database
biweeklybudget.models.base.Base.metadata.reflect(engine)
biweeklybudget.models.base.Base.metadata.drop_all(engine)
biweeklybudget.models.base.Base.metadata.create_all(engine)
def test_0_clean_db(self, dump_file_path):
# clean the database; empty schema
restore_mysqldump(dump_file_path, engine, with_data=False)

def test_01_add(self, testdb):
a = Account(
Expand Down Expand Up @@ -219,6 +220,7 @@ def test_04_notification(self, selenium, base_url):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
@pytest.mark.incremental
class TestBudgetOverBalanceNotification(AcceptanceHelper):

def test_0_update_db(self, testdb):
Expand Down Expand Up @@ -267,6 +269,7 @@ def test_3_notification(self, base_url, selenium):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
@pytest.mark.incremental
class TestPPOverBalanceNotification(AcceptanceHelper):

def test_0_update_db(self, testdb):
Expand Down
106 changes: 32 additions & 74 deletions biweeklybudget/tests/acceptance/flaskapp/views/test_budgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
@pytest.mark.usefixtures('refreshdb', 'testflask')
class TestBudgets(AcceptanceHelper):

@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -102,9 +102,9 @@ def test_initial_data(self, selenium):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditPeriodic1(AcceptanceHelper):
class TestBudgetModals(AcceptanceHelper):

def test_0_verify_db(self, testdb):
def test_00_budget_modal_verify_db(self, testdb):
b = testdb.query(Budget).get(1)
assert b is not None
assert b.name == 'Periodic1'
Expand All @@ -114,7 +114,7 @@ def test_0_verify_db(self, testdb):
assert b.is_active is True
assert b.is_income is False

def test_1_populate_modal(self, base_url, selenium):
def test_01_budget_modal_populate_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Periodic1 (1)"]')
link.click()
Expand All @@ -141,7 +141,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False

def test_2_update_modal(self, base_url, selenium):
def test_02_budget_modal_update_modal(self, base_url, selenium):
# Fill in the form
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Periodic1 (1)"]')
Expand Down Expand Up @@ -182,7 +182,7 @@ def test_2_update_modal(self, base_url, selenium):
'innerHTML') == '<a href="javascript:budgetModal(1, null)">' \
'EditedPeriodic1 (1)</a>'

def test_3_verify_db(self, testdb):
def test_03_budget_modal_verify_db(self, testdb):
b = testdb.query(Budget).get(1)
assert b is not None
assert b.name == 'EditedPeriodic1'
Expand All @@ -192,12 +192,7 @@ def test_3_verify_db(self, testdb):
assert b.is_active is False
assert b.is_income is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditPeriodic2(AcceptanceHelper):

def test_1_populate_modal(self, base_url, selenium):
def test_10_populate_edit_periodic_2_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Periodic2 (2)"]')
link.click()
Expand All @@ -224,12 +219,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditPeriodic3(AcceptanceHelper):

def test_1_populate_modal(self, base_url, selenium):
def test_11_populate_edit_periodic_3_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath(
'//a[text()="Periodic3 Inactive (3)"]'
Expand Down Expand Up @@ -259,12 +249,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditStanding1(AcceptanceHelper):

def test_1_populate_modal(self, base_url, selenium):
def test_12_populate_edit_standing_1_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Standing1 (4)"]')
link.click()
Expand All @@ -291,12 +276,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditStanding2(AcceptanceHelper):

def test_1_populate_modal(self, base_url, selenium):
def test_13_populate_edit_standing_2_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Standing2 (5)"]')
link.click()
Expand All @@ -323,12 +303,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditStanding3(AcceptanceHelper):

def test_1_populate_modal(self, base_url, selenium):
def test_14_populate_edit_standing_3_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath(
'//a[text()="Standing3 Inactive (6)"]'
Expand Down Expand Up @@ -358,12 +333,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestEditIncome(AcceptanceHelper):

def test_0_verify_db(self, testdb):
def test_20_income_verify_db(self, testdb):
b = testdb.query(Budget).get(7)
assert b is not None
assert b.name == 'Income'
Expand All @@ -373,7 +343,7 @@ def test_0_verify_db(self, testdb):
assert b.is_active is True
assert b.is_income is True

def test_1_populate_modal(self, base_url, selenium):
def test_21_populate_income_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Income (7)"]')
link.click()
Expand All @@ -399,7 +369,7 @@ def test_1_populate_modal(self, base_url, selenium):
assert selenium.find_element_by_id('budget_frm_active').is_selected()
assert selenium.find_element_by_id('budget_frm_income').is_selected()

def test_2_update_modal(self, base_url, selenium):
def test_22_update_income_modal(self, base_url, selenium):
# Fill in the form
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_xpath('//a[text()="Income (7)"]')
Expand Down Expand Up @@ -440,7 +410,7 @@ def test_2_update_modal(self, base_url, selenium):
'EditedIncome (7)</a> ' \
'<em class="text-success">(income)</em>'

def test_3_verify_db(self, testdb):
def test_23_verify_income_db(self, testdb):
b = testdb.query(Budget).get(7)
assert b is not None
assert b.name == 'EditedIncome'
Expand All @@ -450,42 +420,33 @@ def test_3_verify_db(self, testdb):
assert b.is_active is False
assert b.is_income is True


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestDirectURLPeriodic1(AcceptanceHelper):

def test_1_populate_modal(self, base_url, selenium):
def test_31_populate_direct_url_modal(self, base_url, selenium):
self.get(selenium, base_url + '/budgets/1')
modal, title, body = self.get_modal_parts(selenium)
self.assert_modal_displayed(modal, title, body)
assert title.text == 'Edit Budget 1'
assert selenium.find_element_by_id('budget_frm_name').get_attribute(
'value') == 'Periodic1'
'value') == 'EditedPeriodic1'
assert selenium.find_element_by_id(
'budget_frm_type_periodic').is_selected()
assert selenium.find_element_by_id(
'budget_frm_type_standing').is_selected() is False
assert selenium.find_element_by_id(
'budget_frm_description').get_attribute('value') == 'P1desc'
'budget_frm_description').get_attribute('value') == 'EditedP1desc'
assert selenium.find_element_by_id(
'budget_frm_starting_balance').get_attribute('value') == '100'
'budget_frm_starting_balance').get_attribute('value') == '2345.67'
assert selenium.find_element_by_id(
'budget_frm_starting_balance_group').is_displayed()
assert selenium.find_element_by_id(
'budget_frm_current_balance').get_attribute('value') == ''
assert selenium.find_element_by_id(
'budget_frm_current_balance_group').is_displayed() is False
assert selenium.find_element_by_id('budget_frm_active').is_selected()
assert selenium.find_element_by_id(
'budget_frm_active').is_selected() is False
assert selenium.find_element_by_id(
'budget_frm_income').is_selected() is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestAddStandingBudget(AcceptanceHelper):

def test_2_update_modal(self, base_url, selenium):
def test_41_add_standing_modal(self, base_url, selenium):
# Fill in the form
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_id('btn_add_budget')
Expand Down Expand Up @@ -527,7 +488,7 @@ def test_2_update_modal(self, base_url, selenium):
'innerHTML') == '<a href="javascript:budgetModal(8, null)">' \
'NewStanding (8)</a>'

def test_3_verify_db(self, testdb):
def test_41_add_standing_verify_db(self, testdb):
b = testdb.query(Budget).get(8)
assert b is not None
assert b.name == 'NewStanding'
Expand All @@ -537,12 +498,7 @@ def test_3_verify_db(self, testdb):
assert b.is_active is True
assert b.is_income is False


@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
class TestAddIncomeBudget(AcceptanceHelper):

def test_2_update_modal(self, base_url, selenium):
def test_51_add_income_modal(self, base_url, selenium):
# Fill in the form
self.get(selenium, base_url + '/budgets')
link = selenium.find_element_by_id('btn_add_budget')
Expand Down Expand Up @@ -573,21 +529,21 @@ def test_2_update_modal(self, base_url, selenium):
_, _, body = self.get_modal_parts(selenium)
x = body.find_elements_by_tag_name('div')[0]
assert 'alert-success' in x.get_attribute('class')
assert x.text.strip() == 'Successfully saved Budget 8 in database.'
assert x.text.strip() == 'Successfully saved Budget 9 in database.'
# dismiss the modal
selenium.find_element_by_id('modalCloseButton').click()
self.wait_for_load_complete(selenium)
self.wait_for_id(selenium, 'table-periodic-budgets')
# test that updated budget was removed from the page
stable = selenium.find_element_by_id('table-periodic-budgets')
selems = self.tbody2elemlist(stable)
assert selems[1][1].get_attribute(
'innerHTML') == '<a href="javascript:budgetModal(8, null)">' \
'NewIncome (8)</a> <em class="text-success">' \
assert selems[2][1].get_attribute(
'innerHTML') == '<a href="javascript:budgetModal(9, null)">' \
'NewIncome (9)</a> <em class="text-success">' \
'(income)</em>'

def test_3_verify_db(self, testdb):
b = testdb.query(Budget).get(8)
def test_52_add_income_verify_db(self, testdb):
b = testdb.query(Budget).get(9)
assert b is not None
assert b.name == 'NewIncome'
assert b.is_periodic is True
Expand All @@ -599,6 +555,7 @@ def test_3_verify_db(self, testdb):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
@pytest.mark.incremental
class TestBudgetTransfer(AcceptanceHelper):

def test_1_verify_db(self, testdb):
Expand Down Expand Up @@ -742,6 +699,7 @@ def test_3_verify_db(self, testdb):

@pytest.mark.acceptance
@pytest.mark.usefixtures('class_refresh_db', 'refreshdb', 'testflask')
@pytest.mark.incremental
class TestBudgetTransferStoP(AcceptanceHelper):

def test_1_verify_db(self, testdb):
Expand Down
Loading

0 comments on commit 7f5edba

Please sign in to comment.