-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor tests and setup #1968
Refactor tests and setup #1968
Changes from 30 commits
1f2185c
ff271a0
8f1dd20
582172d
2e849b5
23119c6
f5e4d39
8d3ee45
095aad0
beceb89
1062b18
3202c58
57794b4
28f79b8
73aea5d
27ab824
7f97018
dbb0743
090e98d
35a0eba
118fdef
5596b72
086f7ca
e370016
ac77cba
b4d91b6
cc65536
5f31115
9b7f110
e60909c
affaab0
92992be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -45,7 +45,7 @@ | |||||||
sample_path = os.path.join(os.path.dirname(__file__), "tests", "data") | ||||||||
shutil.copy(os.path.join(sample_path, "example.ftml"), constants.ROOT_DIR) | ||||||||
|
||||||||
|
||||||||
MSCOLAB_PROCESSES = [] | ||||||||
class TestKeyring(keyring.backend.KeyringBackend): | ||||||||
"""A test keyring which always outputs the same password | ||||||||
from Runtime Configuration | ||||||||
|
@@ -210,32 +210,6 @@ def _load_module(module_name, path): | |||||||
_load_module("mscolab_settings", path) | ||||||||
|
||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing this will Error all tests with an unhandled QMessageBox There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that is true. I just had a test pass with this fixture removed even though it showed a message box and failed with my modified fixture. |
||||||||
@pytest.fixture(autouse=True) | ||||||||
def close_open_windows(): | ||||||||
""" | ||||||||
Closes all windows after every test | ||||||||
""" | ||||||||
# Mock every MessageBox widget in the test suite to avoid unwanted freezes on unhandled error popups etc. | ||||||||
with mock.patch("PyQt5.QtWidgets.QMessageBox.question") as q, \ | ||||||||
mock.patch("PyQt5.QtWidgets.QMessageBox.information") as i, \ | ||||||||
mock.patch("PyQt5.QtWidgets.QMessageBox.critical") as c, \ | ||||||||
mock.patch("PyQt5.QtWidgets.QMessageBox.warning") as w: | ||||||||
yield | ||||||||
if any(box.call_count > 0 for box in [q, i, c, w]): | ||||||||
summary = "\n".join([f"PyQt5.QtWidgets.QMessageBox.{box()._extract_mock_name()}: {box.mock_calls[:-1]}" | ||||||||
for box in [q, i, c, w] if box.call_count > 0]) | ||||||||
warnings.warn(f"An unhandled message box popped up during your test!\n{summary}") | ||||||||
|
||||||||
|
||||||||
# Try to close all remaining widgets after each test | ||||||||
for qobject in set(QtWidgets.QApplication.topLevelWindows() + QtWidgets.QApplication.topLevelWidgets()): | ||||||||
try: | ||||||||
qobject.destroy() | ||||||||
# Some objects deny permission, pass in that case | ||||||||
except RuntimeError: | ||||||||
pass | ||||||||
|
||||||||
|
||||||||
@pytest.fixture(scope="session", autouse=True) | ||||||||
def configure_testsetup(request): | ||||||||
if Display is not None: | ||||||||
|
@@ -248,3 +222,7 @@ def configure_testsetup(request): | |||||||
VIRT_DISPLAY.stop() | ||||||||
else: | ||||||||
yield | ||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the new approach is not to start on any test a mscolab service but once per test class. We need at the end to terminate all processes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that really a good idea? We could run into issues where one test affects the outcome of another due to the shared mscolab instance, which could be a nightmare to debug. Also, I do not really like the implementation with this global variable here, couldn't this be a fixture sort of like this (pseudocode): @pytest.fixture()
def mscolab_server():
server = start_mscolab_server()
yield server
server.shutdown() ? Every test that needs a running mscolab server then should just use the fixture. That way we could even use the scope of the fixture to decide how "shared" we want the instance to be. For what it's worth, I would prefer to get rid of test classes entirely, anyway. A yield fixture is much better suited for setup and teardown code, which leaves classes only as an organizational unit to group tests together. But modules, in turn, do that better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is not a global variable, it is defined as module local variable. we need for xdist calls servers running on different ports, try it. what do you mean by removing test classes entirely, I think setup and teardown may become complicated. But lets see. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. each test cleans up the database, and xdist is currently called on --dist loadfile I also like to have different servers on each run, which I introduced before. Anyway any test needs independent from each other. So not having a test which creates data and another test which tries to vaildate something based on that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The recommended way (by pytest) to have setup and teardown code is using a yield fixture. You can read more about that here: https://docs.pytest.org/en/6.2.x/fixture.html#yield-fixtures-recommended
Hypothetically, what would happen with these shared mscolab servers if we had a test for user deletion trying to delete user "UV10@uv10" in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In Lines 226 to 228 in e60909c
MSCOLAB_PROCESSES a global variable in the scope of the test session, then? We have one instance of this variable in which we accumulate all the running mscolab processes while executing the tests.
If I understand that right, with this PR we would also keep all the processes running until the end of the session, instead of stopping them as soon as they are not needed anymore. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
connect_window and when the tests are paralell running by xdist, any worker creates new tmp dirs We had the described problems before, that's why tests currently not based on some others. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer more functional tests, without using the UI. At least everything what can be tested without the UI should be done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have to disagree on that. We should test at the "level" at which users interact with the application as well, and that is the UI. There is no point in testing if a login works if we don't test that the actual login button works also. Or to phrase it differently: everything that can be done with the UI cannot be tested without it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we do UI tests already in many ways also by the tutorials, But we also have a lot helper functions which also work without the UI and these should become tested if possibile without the UI. |
||||||||
def pytest_sessionfinish(session, exitstatus): | ||||||||
for process in MSCOLAB_PROCESSES: | ||||||||
process.terminate() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1056,8 +1056,11 @@ def handle_delete_operation(self): | |
self.reload_operations() | ||
self.signal_operation_removed.emit(self.active_op_id) | ||
logging.debug("activate local") | ||
self.ui.listFlightTracks.setCurrentRow(0) | ||
self.ui.activate_selected_flight_track() | ||
if self.ui.listFlightTracks.count() == 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in mscolab we can remove "all" operations from the list, while we can't in the local flight path (left site of the UI) |
||
self.switch_to_local() | ||
else: | ||
self.ui.listFlightTracks.setCurrentRow(0) | ||
self.ui.activate_selected_flight_track() | ||
else: | ||
show_popup(self.ui, "Error", "Entered operation name did not match!") | ||
else: | ||
|
@@ -1131,7 +1134,7 @@ def change_category_handler(self): | |
self.active_operation_category = entered_operation_category | ||
self.reload_operation_list() | ||
self.error_dialog = QtWidgets.QErrorMessage() | ||
self.error_dialog.showMessage("Description is updated successfully.") | ||
self.error_dialog.showMessage("Category is updated successfully.") | ||
else: | ||
show_popup(self.ui, "Error", "Your Connection is expired. New Login required!") | ||
self.logout() | ||
|
@@ -1986,11 +1989,9 @@ def logout(self): | |
|
||
self.operation_archive_browser.hide() | ||
|
||
# Don't try to activate local flighttrack while testing | ||
if "pytest" not in sys.modules: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not needed when the tests and code are updated |
||
# activate first local flighttrack after logging out | ||
self.ui.listFlightTracks.setCurrentRow(0) | ||
self.ui.activate_selected_flight_track() | ||
# activate first local flighttrack after logging out | ||
self.ui.listFlightTracks.setCurrentRow(0) | ||
self.ui.activate_selected_flight_track() | ||
|
||
|
||
class MscolabMergeWaypointsDialog(QtWidgets.QDialog, merge_wp_ui.Ui_MergeWaypointsDialog): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently will loose all tests assigned to a worker when that crashes