Skip to content

Commit f54a6bf

Browse files
michaelchuclaude
andcommitted
Fix CLI tests missing mocks for _load_env, dotenv, and requests
TestCmdRun tests called _cmd_run() without mocking _load_env(), which tries to import dotenv. TestCmdDownload and test_cli_extra tests imported eodhd/requests at module level. Fixed by mocking _load_env, import_optional_dependency, and the eodhd module in sys.modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6ede09a commit f54a6bf

File tree

2 files changed

+50
-15
lines changed

2 files changed

+50
-15
lines changed

tests/test_cli.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ def test_host_port_env_vars(self, tmp_path):
155155
"optopsy.ui._compat.import_optional_dependency",
156156
mock_compat.import_optional_dependency,
157157
),
158+
patch("optopsy.ui.cli._load_env"),
158159
patch.dict(os.environ, controlled_env, clear=True),
159160
):
160161
_cmd_run(args)
@@ -192,6 +193,7 @@ def test_auth_secret_generation_writes_to_file(self):
192193
"optopsy.ui._compat.import_optional_dependency",
193194
mock_compat.import_optional_dependency,
194195
),
196+
patch("optopsy.ui.cli._load_env"),
195197
patch.dict(os.environ, env_copy, clear=True),
196198
patch("optopsy.ui.paths.AUTH_SECRET_PATH", mock_path),
197199
):
@@ -230,6 +232,7 @@ def test_auth_secret_read_from_file(self):
230232
"optopsy.ui._compat.import_optional_dependency",
231233
mock_compat.import_optional_dependency,
232234
),
235+
patch("optopsy.ui.cli._load_env"),
233236
patch.dict(os.environ, env_copy, clear=True),
234237
patch("optopsy.ui.paths.AUTH_SECRET_PATH", mock_path),
235238
):
@@ -259,6 +262,7 @@ def test_chainlit_config_set(self):
259262
"optopsy.ui._compat.import_optional_dependency",
260263
mock_compat.import_optional_dependency,
261264
),
265+
patch("optopsy.ui.cli._load_env"),
262266
patch.dict(os.environ, {"CHAINLIT_AUTH_SECRET": "test"}, clear=False),
263267
):
264268
_cmd_run(args)
@@ -290,6 +294,7 @@ def test_run_chainlit_called_with_app_path(self):
290294
"optopsy.ui._compat.import_optional_dependency",
291295
mock_compat.import_optional_dependency,
292296
),
297+
patch("optopsy.ui.cli._load_env"),
293298
patch.dict(os.environ, {"CHAINLIT_AUTH_SECRET": "test"}, clear=False),
294299
):
295300
_cmd_run(args)
@@ -422,11 +427,17 @@ def test_no_provider_prints_error(self, capsys):
422427

423428
args = argparse.Namespace(symbols=["SPY"], verbose=False)
424429

430+
mock_eodhd = MagicMock()
431+
425432
with (
426433
patch(
427434
"optopsy.data._compat.import_optional_dependency",
428435
),
429436
patch("optopsy.data.cli._load_env"),
437+
patch.dict(
438+
sys.modules,
439+
{"optopsy.data.providers.eodhd": mock_eodhd},
440+
),
430441
patch(
431442
"optopsy.data.providers.get_provider_for_tool",
432443
return_value=None,

tests/test_cli_extra.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for optopsy/data/cli.py — additional coverage for download and cache commands."""
22

33
import argparse
4+
import sys
45

56
import pytest
67

@@ -32,13 +33,19 @@ def test_format_bytes_gb():
3233
# ---------------------------------------------------------------------------
3334

3435

35-
@patch("dotenv.find_dotenv", return_value="")
36-
@patch("dotenv.load_dotenv")
37-
def test_load_env_fallback(mock_load, mock_find):
36+
def test_load_env_fallback():
3837
"""When find_dotenv returns empty string, should use fallback path."""
39-
_load_env()
40-
mock_load.assert_called_once()
41-
call_path = mock_load.call_args[0][0]
38+
mock_dotenv = MagicMock()
39+
mock_dotenv.find_dotenv.return_value = ""
40+
41+
with patch(
42+
"optopsy.data._compat.import_optional_dependency",
43+
return_value=mock_dotenv,
44+
):
45+
_load_env()
46+
47+
mock_dotenv.load_dotenv.assert_called_once()
48+
call_path = mock_dotenv.load_dotenv.call_args[0][0]
4249
assert call_path.endswith(".env")
4350
assert len(call_path) > 4
4451

@@ -48,28 +55,45 @@ def test_load_env_fallback(mock_load, mock_find):
4855
# ---------------------------------------------------------------------------
4956

5057

51-
@patch("optopsy.data.cli._load_env")
52-
@patch("optopsy.data.providers.get_provider_for_tool", return_value=None)
53-
def test_cmd_download_no_provider(mock_get_provider, mock_env, capsys):
58+
def test_cmd_download_no_provider(capsys):
5459
"""When no provider is configured, should print an error."""
60+
mock_eodhd = MagicMock()
5561
args = argparse.Namespace(symbols=["SPY"], verbose=False)
56-
_cmd_download(args)
62+
63+
with (
64+
patch("optopsy.data._compat.import_optional_dependency"),
65+
patch("optopsy.data.cli._load_env"),
66+
patch.dict(sys.modules, {"optopsy.data.providers.eodhd": mock_eodhd}),
67+
patch("optopsy.data.providers.get_provider_for_tool", return_value=None),
68+
):
69+
_cmd_download(args)
70+
5771
captured = capsys.readouterr()
5872
assert "No data provider" in captured.out
5973

6074

61-
@patch("optopsy.data.cli._load_env")
62-
@patch("optopsy.data.providers.get_provider_for_tool")
63-
def test_cmd_download_generic_provider(mock_get_provider, mock_env, capsys):
75+
def test_cmd_download_generic_provider(capsys):
6476
"""Non-EODHD provider should use the generic download path."""
77+
mock_eodhd = MagicMock()
78+
# Provide a real class so isinstance() works in _cmd_download
79+
mock_eodhd.EODHDProvider = type("EODHDProvider", (), {})
6580
mock_provider = MagicMock(
6681
spec=[]
6782
) # empty spec so isinstance(EODHDProvider) is False
6883
mock_provider.execute = MagicMock(return_value=("Downloaded 100 rows", None))
69-
mock_get_provider.return_value = mock_provider
7084

7185
args = argparse.Namespace(symbols=["SPY", "AAPL"], verbose=False)
72-
_cmd_download(args)
86+
87+
with (
88+
patch("optopsy.data._compat.import_optional_dependency"),
89+
patch("optopsy.data.cli._load_env"),
90+
patch.dict(sys.modules, {"optopsy.data.providers.eodhd": mock_eodhd}),
91+
patch(
92+
"optopsy.data.providers.get_provider_for_tool",
93+
return_value=mock_provider,
94+
),
95+
):
96+
_cmd_download(args)
7397

7498
assert mock_provider.execute.call_count == 2
7599
captured = capsys.readouterr()

0 commit comments

Comments
 (0)