Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
23 changes: 23 additions & 0 deletions LabGym/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
/tests/conftest.py

Shared pytest fixtures for LabGym tests
"""

# Standard library imports
import sys

# Related third party imports
import pytest

@pytest.fixture(scope="session")
def wx_app():
from LabGym import mywx
import wx
app = wx.App()
yield app


@pytest.fixture
def mock_argv(monkeypatch):
monkeypatch.setattr(sys, 'argv', ['LabGym'])
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions tests/unit/test___main__.py → LabGym/tests/unit/test___main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import sys
import time
from unittest.mock import MagicMock

from packaging import version

Expand Down Expand Up @@ -107,6 +108,30 @@ def test_main_stale_labgym(monkeypatch):
# This unit test passes if __main__.main doesn't raise an exception.


def test_main_selftest_flag_exits_with_result(monkeypatch):
"""When config has selftest True, main calls run_selftests and exits with its return code."""
from LabGym import mylogging
monkeypatch.setattr(mylogging, 'configure', lambda *args: None)

from LabGym import __main__
monkeypatch.setattr(__main__.probes, 'probes', lambda: None)
monkeypatch.setattr(__main__.gui_main, 'main_window', lambda: None)
monkeypatch.setattr(__main__.wx, 'GetApp', lambda: None)
monkeypatch.setattr(__main__.wx, 'App', lambda: None)

monkeypatch.setattr(__main__.config, 'get_config', lambda: {'selftest': True})
run_selftests_mock = MagicMock(return_value=0)
monkeypatch.setattr(__main__.selftest, 'run_selftests', run_selftests_mock)
exit_mock = MagicMock(side_effect=SystemExit(0))
monkeypatch.setattr(sys, 'exit', exit_mock)

with pytest.raises(SystemExit):
__main__.main()

run_selftests_mock.assert_called_once()
exit_mock.assert_called_once_with(0)


# from .exitstatus import exitstatus
#
# # Specify sys.argv before importing __main__. Why? Because the
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 2 additions & 5 deletions tests/unit/test_load.py → LabGym/tests/unit/test_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,12 @@ def test_import_LabGym_package():
submodules.extend(['detectron2', 'mywx', 'pkghash', 'selftest'])


def test_imports_with_sysargv_initialized(monkeypatch):
def test_imports_with_sysargv_initialized(mock_argv):
"""Test that some module imports don't raise exceptions.

These module imports must be tested with sys.argv initialized.
"""
# Arrange sys.argv. Otherwise sys.argv contains pytest args, and
# myargparse raises an exception.
monkeypatch.setattr(sys, 'argv', ['dummy'])


# Act
logging.info('import LabGym.__main__')
import LabGym.__main__
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,17 @@ def test_enable_(monkeypatch):

# Assert
assert result == {'enable': {'F1': False, 'F2': True}}


def test_parse_args_selftest(monkeypatch):
"""--selftest sets selftest flag so bundled/CLI selftest path is used."""
# Arrange
monkeypatch.setattr(sys, 'argv', ['cmd', '--selftest'])

# Act
result = myargparse.parse_args()

# Assert
assert result == {'selftest': True}


File renamed without changes.
1 change: 1 addition & 0 deletions tests/unit/test_mywx.py → LabGym/tests/unit/test_mywx.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from LabGym import mywx # on load, monkeypatch wx.App to be a singleton
import wx # wxPython, Cross platform GUI toolkit for Python, "Phoenix" version

pytestmark = pytest.mark.gui # All tests require wx

# testdir = Path(__file__[:-3]) # dir containing support files for unit tests
# assert testdir.is_dir()
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def test_dummy():
# Assert not necessary. This unit test passes unless exception was raised.


@pytest.mark.gui
def test_mydialog_skip(wx_app):
frame = wx.Frame(None) # parent for the dialog
dialog = registration.RegFormDialog(frame)
Expand Down Expand Up @@ -70,6 +71,7 @@ def click_skip():
dialog.Destroy() # request the dialog to self-destruct


@pytest.mark.gui
def test_mydialog_register(wx_app):
frame = wx.Frame(None) # parent for the dialog
dialog = registration.RegFormDialog(frame)
Expand Down Expand Up @@ -114,6 +116,7 @@ def enter_email():
dialog.Destroy() # request the dialog to self-destruct


@pytest.mark.gui
def test__get_reginfo_from_form(monkeypatch, wx_app, tmp_path):

# frame = wx.Frame(None) # parent for the dialog
Expand Down
78 changes: 78 additions & 0 deletions LabGym/tests/unit/test_selftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
LabGym.tests.unit.test_selftest

The selftest feature allows testing a (future) bundled PyInstaller build and
running the package's tests on itself (e.g. LabGym --selftest)
"""

# Standard library imports
import logging

# Related third party imports
from unittest.mock import MagicMock, patch
import pytest
import wx

# Local application/library specific imports
from LabGym import selftest

logger = logging.getLogger(__name__)


def test_selftest_module_exports():
"""Selftest module exposes the expected public API."""
assert hasattr(selftest, 'run_selftests')
assert hasattr(selftest, 'run_selftests_help')
assert callable(selftest.run_selftests)
assert callable(selftest.run_selftests_help)


@patch.object(selftest.selftest, 'pytest')
def test_run_selftest_returns_0_when_all_pass(mock_pytest):
"""When all pytest runs pass, run_selftests returns 0."""
mock_pytest.main.return_value = 0

result = selftest.run_selftests()

assert result == 0
assert mock_pytest.main.call_count >= 1


@patch.object(selftest.selftest, 'pytest')
def test_run_selftest_returns_1_when_some_fail(mock_pytest):
"""When any pytest run fails, run_selftests returns 1."""
# First call (this file) passes, second (LabGym.tests) fails
mock_pytest.main.side_effect = [0, 1]

result = selftest.run_selftests()

assert result == 1


@patch.object(selftest.selftest, 'pytest')
def test_run_selftests_invokes_pytest_with_pyargs(mock_pytest):
"""run_selftests invokes pytest with --pyargs LabGym.tests for package tests."""
mock_pytest.main.return_value = 0

selftest.run_selftests()

# At least one call should be with --pyargs and LabGym.tests
call_args_list = [call[0][0] for call in mock_pytest.main.call_args_list]

assert any('--pyargs' in args and 'LabGym.tests' in args for args in call_args_list)


@patch.object(selftest.selftest, 'mywx')
def test_run_selftests_help_does_not_raise(mock_mywx):
"""run_selftests_help runs without raising (dialog is mocked)"""
mock_dlg = MagicMock()
mock_dlg.__enter__ = MagicMock(return_value = mock_dlg)
mock_dlg.__exit__ = MagicMock(return_value = None)
mock_dlg.ShowModal.return_value = wx.ID_OK
mock_mywx.OK_Cancel_Dialog.return_value = mock_dlg

selftest.run_selftests_help()

mock_mywx.OK_Cancel_Dialog.assert_called_once()
mock_dlg.ShowModal.assert_called_once()

Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def test_get_list_of_subdirs(tmp_path):


# def assert_userdata_dirs_are_separate(
@pytest.mark.gui
def test_assert_userdata_dirs_are_separate(
monkeypatch, tmp_path, wx_app, caplog):
"""Violate the assertion by passing in equivalent path1 & path2."""
Expand All @@ -153,6 +154,7 @@ def test_assert_userdata_dirs_are_separate(


# def survey(
@pytest.mark.gui
def test_survey_case1(monkeypatch, tmp_path, wx_app, caplog):
"""violate check 1, and get SystemExit."""
# Arrange
Expand Down Expand Up @@ -182,6 +184,7 @@ def test_survey_case1(monkeypatch, tmp_path, wx_app, caplog):
assert expected_msg in caplog.text


@pytest.mark.gui
def test_survey_case2(monkeypatch, tmp_path, wx_app, caplog):
"""violate check 2, and get Warning."""
# Arrange
Expand All @@ -204,6 +207,7 @@ def test_survey_case2(monkeypatch, tmp_path, wx_app, caplog):
assert expected_msg in caplog.text


@pytest.mark.gui
def test_survey_case3(monkeypatch, tmp_path, wx_app, caplog):
"""violate check 3, and get Warning."""
# Arrange
Expand All @@ -225,6 +229,7 @@ def test_survey_case3(monkeypatch, tmp_path, wx_app, caplog):
assert expected_msg in caplog.text


@pytest.mark.gui
def test_survey_case4(monkeypatch, tmp_path, wx_app, caplog):
"""violate check 4, and get Warning."""
# Arrange
Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def tests(session:nox.Session):

# package and test dependencies
session.install("-e", ".")
session.install("pytest", "coverage")
session.install("coverage")


session.run("pytest", "-q")
Expand Down
4 changes: 2 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# pytest.ini
[pytest]
testpaths = tests
testpaths = LabGym/tests

markers =
slow: marks tests as slow
integration: markts integration tests
integration: marks integration tests
gui: marks tests requiring wx

# Avoid two coverage warnings from detectron2's import of cv2.
Expand Down
45 changes: 0 additions & 45 deletions tests/conftest.py

This file was deleted.

19 changes: 0 additions & 19 deletions tests/linting/INIT.sh

This file was deleted.

Loading