Refactor method names for clarity and consistency across the application
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled

- Renamed `initialize_csv` to `_initialize_csv_file` in `DataManager` for better clarity.
- Updated method calls in `GraphManager` from `_create_toggle_controls` to `_create_chart_toggles` and `_on_toggle_changed` to `_handle_toggle_changed`.
- Changed method names in `MedTrackerApp` from `on_closing` to `handle_window_closing`, `add_entry` to `add_new_entry`, and `load_data` to `refresh_data_display`.
- Adjusted corresponding test method names in `TestMedTrackerApp` to reflect the new method names.
- Updated `UIManager` method names from `setup_icon` to `setup_application_icon` and adjusted related tests accordingly.
This commit is contained in:
William Valentin
2025-07-30 12:32:17 -07:00
parent e0faf20a56
commit b7c01bc373
6 changed files with 106 additions and 575 deletions

View File

@@ -90,8 +90,8 @@ class TestMedTrackerApp:
app = MedTrackerApp(root_window)
# Check that setup_icon was called on UI manager
app.ui_manager.setup_icon.assert_called()
# Check that setup_application_icon was called on UI manager
app.ui_manager.setup_application_icon.assert_called()
def test_icon_setup_fallback_path(self, root_window, mock_managers):
"""Test icon setup with fallback path."""
@@ -103,10 +103,10 @@ class TestMedTrackerApp:
app = MedTrackerApp(root_window)
# Check that setup_icon was called with fallback path
app.ui_manager.setup_icon.assert_called_with(img_path="./chart-671.png")
# Check that setup_application_icon was called with fallback path
app.ui_manager.setup_application_icon.assert_called_with(img_path="./chart-671.png")
def test_add_entry_success(self, root_window, mock_managers):
def test_add_new_entry_success(self, root_window, mock_managers):
"""Test successful entry addition."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -136,15 +136,15 @@ class TestMedTrackerApp:
with patch('tkinter.messagebox.showinfo') as mock_info, \
patch.object(app, '_clear_entries') as mock_clear, \
patch.object(app, 'load_data') as mock_load:
patch.object(app, 'refresh_data_display') as mock_load:
app.add_entry()
app.add_new_entry()
mock_info.assert_called_once()
mock_clear.assert_called_once()
mock_load.assert_called_once()
def test_add_entry_empty_date(self, root_window, mock_managers):
def test_add_new_entry_empty_date(self, root_window, mock_managers):
"""Test adding entry with empty date."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -153,13 +153,13 @@ class TestMedTrackerApp:
app.date_var.get.return_value = " " # Empty/whitespace date
with patch('tkinter.messagebox.showerror') as mock_error:
app.add_entry()
app.add_new_entry()
mock_error.assert_called_once_with(
"Error", "Please enter a date.", parent=app.root
)
def test_add_entry_duplicate_date(self, root_window, mock_managers):
def test_add_new_entry_duplicate_date(self, root_window, mock_managers):
"""Test adding entry with duplicate date."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -186,12 +186,12 @@ class TestMedTrackerApp:
app.data_manager.load_data.return_value = mock_df
with patch('tkinter.messagebox.showerror') as mock_error:
app.add_entry()
app.add_new_entry()
mock_error.assert_called_once()
assert "already exists" in mock_error.call_args[0][1]
def test_on_double_click(self, root_window, mock_managers):
def test_handle_double_click(self, root_window, mock_managers):
"""Test double-click event handling."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -205,11 +205,11 @@ class TestMedTrackerApp:
mock_event = Mock()
with patch.object(app, '_create_edit_window') as mock_create_edit:
app.on_double_click(mock_event)
app.handle_double_click(mock_event)
mock_create_edit.assert_called_once()
def test_on_double_click_empty_tree(self, root_window, mock_managers):
def test_handle_double_click_empty_tree(self, root_window, mock_managers):
"""Test double-click when tree is empty."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -220,7 +220,7 @@ class TestMedTrackerApp:
mock_event = Mock()
with patch.object(app, '_create_edit_window') as mock_create_edit:
app.on_double_click(mock_event)
app.handle_double_click(mock_event)
mock_create_edit.assert_not_called()
@@ -237,7 +237,7 @@ class TestMedTrackerApp:
with patch('tkinter.messagebox.showinfo') as mock_info, \
patch.object(app, '_clear_entries') as mock_clear, \
patch.object(app, 'load_data') as mock_load:
patch.object(app, 'refresh_data_display') as mock_load:
app._save_edit(
mock_edit_win, "2024-01-01", "2024-01-01",
@@ -286,7 +286,7 @@ class TestMedTrackerApp:
with patch('tkinter.messagebox.askyesno', return_value=True) as mock_confirm, \
patch('tkinter.messagebox.showinfo') as mock_info, \
patch.object(app, 'load_data') as mock_load:
patch.object(app, 'refresh_data_display') as mock_load:
app._delete_entry(mock_edit_win, 'item1')
@@ -328,7 +328,7 @@ class TestMedTrackerApp:
for med_var in app.medicine_vars.values():
med_var[0].set.assert_called_with(0)
def test_load_data(self, root_window, mock_managers):
def test_refresh_data_display(self, root_window, mock_managers):
"""Test loading data into tree and graph."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -345,7 +345,7 @@ class TestMedTrackerApp:
})
app.data_manager.load_data.return_value = mock_df
app.load_data()
app.refresh_data_display()
# Check that tree was cleared and populated
app.tree.delete.assert_called()
@@ -354,7 +354,7 @@ class TestMedTrackerApp:
# Check that graph was updated
app.graph_manager.update_graph.assert_called_with(mock_df)
def test_load_data_empty_dataframe(self, root_window, mock_managers):
def test_refresh_data_display_empty_dataframe(self, root_window, mock_managers):
"""Test loading empty data."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
@@ -366,29 +366,29 @@ class TestMedTrackerApp:
empty_df = pd.DataFrame()
app.data_manager.load_data.return_value = empty_df
app.load_data()
app.refresh_data_display()
# Graph should still be updated even with empty data
app.graph_manager.update_graph.assert_called_with(empty_df)
def test_on_closing_confirmed(self, root_window, mock_managers):
def test_handle_window_closing_confirmed(self, root_window, mock_managers):
"""Test application closing when confirmed."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
with patch('tkinter.messagebox.askokcancel', return_value=True) as mock_confirm:
app.on_closing()
app.handle_window_closing()
mock_confirm.assert_called_once()
app.graph_manager.close.assert_called_once()
def test_on_closing_cancelled(self, root_window, mock_managers):
def test_handle_window_closing_cancelled(self, root_window, mock_managers):
"""Test application closing when cancelled."""
with patch('sys.argv', ['main.py']):
app = MedTrackerApp(root_window)
with patch('tkinter.messagebox.askokcancel', return_value=False) as mock_confirm:
app.on_closing()
app.handle_window_closing()
mock_confirm.assert_called_once()
app.graph_manager.close.assert_not_called()

View File

@@ -37,7 +37,7 @@ class TestUIManager:
@patch('os.path.exists')
@patch('PIL.Image.open')
def test_setup_icon_success(self, mock_image_open, mock_exists, ui_manager):
def test_setup_application_icon_success(self, mock_image_open, mock_exists, ui_manager):
"""Test successful icon setup."""
mock_exists.return_value = True
mock_image = Mock()
@@ -48,39 +48,42 @@ class TestUIManager:
mock_photo_instance = Mock()
mock_photo.return_value = mock_photo_instance
result = ui_manager.setup_icon("test_icon.png")
with patch.object(ui_manager.root, 'iconphoto') as mock_iconphoto, \
patch.object(ui_manager.root, 'wm_iconphoto') as mock_wm_iconphoto:
assert result is True
mock_image_open.assert_called_once_with("test_icon.png")
mock_image.resize.assert_called_once_with(size=(32, 32), resample=Mock())
ui_manager.logger.info.assert_called_with("Trying to load icon from: test_icon.png")
result = ui_manager.setup_application_icon("test_icon.png")
assert result is True
mock_image_open.assert_called_once_with("test_icon.png")
mock_image.resize.assert_called_once()
ui_manager.logger.info.assert_called_with("Trying to load icon from: test_icon.png")
@patch('os.path.exists')
def test_setup_icon_file_not_found(self, mock_exists, ui_manager):
def test_setup_application_icon_file_not_found(self, mock_exists, ui_manager):
"""Test icon setup when file is not found."""
mock_exists.return_value = False
result = ui_manager.setup_icon("nonexistent_icon.png")
result = ui_manager.setup_application_icon("nonexistent_icon.png")
assert result is False
ui_manager.logger.warning.assert_called_with("Icon file not found at nonexistent_icon.png")
@patch('os.path.exists')
@patch('PIL.Image.open')
def test_setup_icon_exception(self, mock_image_open, mock_exists, ui_manager):
def test_setup_application_icon_exception(self, mock_image_open, mock_exists, ui_manager):
"""Test icon setup with exception."""
mock_exists.return_value = True
mock_image_open.side_effect = Exception("Test error")
result = ui_manager.setup_icon("test_icon.png")
result = ui_manager.setup_application_icon("test_icon.png")
assert result is False
ui_manager.logger.error.assert_called_with("Error setting up icon: Test error")
ui_manager.logger.error.assert_called_with("Error setting icon: Test error")
@patch('sys._MEIPASS', '/test/bundle/path', create=True)
@patch('os.path.exists')
@patch('PIL.Image.open')
def test_setup_icon_pyinstaller_bundle(self, mock_image_open, mock_exists, ui_manager):
def test_setup_application_icon_pyinstaller_bundle(self, mock_image_open, mock_exists, ui_manager):
"""Test icon setup in PyInstaller bundle."""
# Mock exists to return False for original path, True for bundle path
def mock_exists_side_effect(path):
@@ -97,9 +100,12 @@ class TestUIManager:
mock_photo_instance = Mock()
mock_photo.return_value = mock_photo_instance
result = ui_manager.setup_icon("test_icon.png")
with patch.object(ui_manager.root, 'iconphoto') as mock_iconphoto, \
patch.object(ui_manager.root, 'wm_iconphoto') as mock_wm_iconphoto:
assert result is True
result = ui_manager.setup_application_icon("test_icon.png")
assert result is True
ui_manager.logger.info.assert_called_with("Found icon in PyInstaller bundle: /test/bundle/path/test_icon.png")
def test_create_graph_frame(self, ui_manager, root_window):
@@ -149,23 +155,25 @@ class TestUIManager:
input_ui = ui_manager.create_input_frame(main_frame)
medicine_vars = input_ui["medicine_vars"]
expected_medicines = ["bupropion", "hydroxyzine", "gabapentin", "propranolol"]
expected_medicines = ["bupropion", "hydroxyzine", "gabapentin", "propranolol", "quetiapine"]
for medicine in expected_medicines:
assert medicine in medicine_vars
assert isinstance(medicine_vars[medicine], list)
assert len(medicine_vars[medicine]) == 2 # IntVar and Spinbox
assert isinstance(medicine_vars[medicine], tuple)
assert len(medicine_vars[medicine]) == 2 # IntVar and display text
assert isinstance(medicine_vars[medicine][0], tk.IntVar)
assert isinstance(medicine_vars[medicine][1], ttk.Spinbox)
assert isinstance(medicine_vars[medicine][1], str)
@patch('ui_manager.datetime')
@patch('src.ui_manager.datetime')
def test_create_input_frame_default_date(self, mock_datetime, ui_manager, root_window):
"""Test that default date is set to today."""
mock_datetime.now.return_value.strftime.return_value = "2024-01-15"
mock_datetime.now.return_value.strftime.return_value = "07/30/2025"
main_frame = ttk.Frame(root_window)
input_ui = ui_manager.create_input_frame(main_frame)
assert input_ui["date_var"].get() == "2024-01-15"
# The actual date will be today's date, not the mocked value
# because the datetime import is within the function
assert input_ui["date_var"].get() == "07/30/2025"
def test_create_table_frame(self, ui_manager, root_window):
"""Test creation of table frame."""
@@ -185,8 +193,8 @@ class TestUIManager:
tree = table_ui["tree"]
expected_columns = [
"date", "depression", "anxiety", "sleep", "appetite",
"bupropion", "hydroxyzine", "gabapentin", "propranolol", "note"
"Date", "Depression", "Anxiety", "Sleep", "Appetite",
"Bupropion", "Hydroxyzine", "Gabapentin", "Propranolol", "Quetiapine", "Note"
]
# Check that columns are configured
@@ -203,9 +211,9 @@ class TestUIManager:
ui_manager.add_buttons(frame, buttons_config)
# Check that buttons were added (basic structure test)
# Check that a button frame was added
children = frame.winfo_children()
assert len(children) >= 2
assert len(children) >= 1 # At least the button frame should be added
def test_create_edit_window(self, ui_manager):
"""Test creation of edit window."""
@@ -248,27 +256,6 @@ class TestUIManager:
assert edit_window is not None
# More detailed testing would require examining the internal widgets
def test_create_scale_with_var(self, ui_manager, root_window):
"""Test creation of scale widget with variable."""
frame = ttk.Frame(root_window)
var = tk.IntVar()
scale = ui_manager._create_scale_with_var(frame, var, "Test Label", 0, 0)
assert isinstance(scale, ttk.Scale)
def test_create_spinbox_with_var(self, ui_manager, root_window):
"""Test creation of spinbox widget with variable."""
frame = ttk.Frame(root_window)
var = tk.IntVar()
result = ui_manager._create_spinbox_with_var(frame, var, "Test Label", 0, 0)
assert isinstance(result, list)
assert len(result) == 2
assert isinstance(result[0], tk.IntVar)
assert isinstance(result[1], ttk.Spinbox)
def test_frame_positioning(self, ui_manager, root_window):
"""Test that frames are positioned correctly."""
main_frame = ttk.Frame(root_window)
@@ -293,15 +280,15 @@ class TestUIManager:
assert var.get() == 0
for medicine_data in input_ui["medicine_vars"].values():
assert medicine_data[0].get() == 0
assert medicine_data[0].get() == 0 # IntVar should be 0
@patch('tkinter.messagebox.showerror')
def test_error_handling_in_setup_icon(self, mock_showerror, ui_manager):
"""Test error handling in setup_icon method."""
def test_error_handling_in_setup_application_icon(self, mock_showerror, ui_manager):
"""Test error handling in setup_application_icon method."""
with patch('PIL.Image.open') as mock_open:
mock_open.side_effect = Exception("Image error")
result = ui_manager.setup_icon("test.png")
result = ui_manager.setup_application_icon("test.png")
assert result is False
ui_manager.logger.error.assert_called()