test: reduce test_trading.py duplication with parametrize (#64)

* test: reduce test_trading.py duplication with parametrize

Collapse repetitive individual tests in test_trading.py into
parametrized equivalents, cutting 267 lines without losing any cases.

- TestExtractTickPrice: 13 tests → 2 parametrized (×3 valid, ×10 None)
- TestEstimateOrderMargin: 4 invalid-margin tests → 1 parametrized ×4;
  nan/inf volume tests → 1 parametrized ×2
- TestNormalizeOrderVolume: multi-assert bodies split into parametrized
  cases for non-finite volume and constraints
- TestVolumeAndExecution: 9 place_market_order retcode tests → 1 ×11;
  5 update_sltp retcode tests → 1 ×5
- test_calculate_trailing_stop_updates_missing_symbol_digits:
  inline double-assert body → 1 parametrized ×2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: further reduce test_trading.py duplication with parametrize

Merge six broker stop-level tests into two parametrized tests, collapse
two default-digits fallback tests and three symbol-filter zero-margin
tests into one each.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: address claude[bot] review on PR #64

- Consolidate _MISSING_RETCODE sentinel to one line with corrected comment
- Add comment explaining ids list is required for deterministic node IDs
- Document intentional narrower retcode coverage in update_sltp test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: reduce duplication in test_sdk, test_history, test_contracts

- TestBuildConfigWholeDollarEnv: 3 field tests (server/password/path) → 1
  parametrized ×3
- TestResolveAccountSpec: whole-dollar expand/no-expand pair → 1 parametrized ×2
- test_normalize_mt5_exception_maps_types: 2 isinstance asserts → parametrized ×2
- test_resolve_history_tick_flags_invalid: 2 pytest.raises blocks → parametrized ×2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: agent <agent@localhost>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Daichi Narushima
2026-06-25 01:55:04 +09:00
committed by GitHub
co-authored by Claude Sonnet 4.6 agent
parent 37eef16e99
commit 15bfd17db3
4 changed files with 307 additions and 677 deletions
+31 -43
View File
@@ -1938,29 +1938,28 @@ class TestResolveAccountSpec:
assert [a.server for a in resolved] == ["Shared", "Fixed"]
assert all(a.timeout == 1000 for a in resolved)
def test_resolve_account_spec_with_whole_dollar_env(
@pytest.mark.parametrize(
("allow_whole_dollar_env", "expected"),
[
(True, "secret"),
(False, "$MT5_PASSWORD"),
],
)
def test_resolve_account_spec_whole_dollar_password(
self,
monkeypatch: pytest.MonkeyPatch,
allow_whole_dollar_env: bool,
expected: str,
) -> None:
"""Account spec expands $ENV_NAME when allow_whole_dollar_env=True."""
"""Test resolve_account_spec expands $ENV_NAME password only with opt-in."""
monkeypatch.setenv("MT5_PASSWORD", "secret")
account = AccountSpec(symbols=["EURUSD"], password="$MT5_PASSWORD")
resolved = resolve_account_spec(account, allow_whole_dollar_env=True)
resolved = resolve_account_spec(
account, allow_whole_dollar_env=allow_whole_dollar_env
)
assert resolved.password == "secret" # noqa: S105
def test_resolve_account_spec_whole_dollar_not_expanded_by_default(
self,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test resolve_account_spec leaves $ENV_NAME literal by default."""
monkeypatch.setenv("MT5_PASSWORD", "secret")
account = AccountSpec(symbols=["EURUSD"], password="$MT5_PASSWORD")
resolved = resolve_account_spec(account)
assert resolved.password == "$MT5_PASSWORD" # noqa: S105
assert resolved.password == expected
def test_resolve_account_specs_with_whole_dollar_env(
self,
@@ -1994,38 +1993,27 @@ class TestResolveAccountSpec:
class TestBuildConfigWholeDollarEnv:
"""Tests for build_config with allow_whole_dollar_env."""
def test_build_config_substitutes_server_with_opt_in(
@pytest.mark.parametrize(
("env_var", "field", "env_value"),
[
("MT5_SERVER", "server", "Broker-Demo"),
("MT5_PASSWORD", "password", "secret"),
("MT5_PATH", "path", "/opt/mt5/terminal64.exe"),
],
)
def test_build_config_substitutes_field_with_opt_in(
self,
monkeypatch: pytest.MonkeyPatch,
env_var: str,
field: str,
env_value: str,
) -> None:
"""build_config expands $ENV_NAME server when allow_whole_dollar_env=True."""
monkeypatch.setenv("MT5_SERVER", "Broker-Demo")
"""Test build_config expands $ENV_NAME fields when opt-in is enabled."""
monkeypatch.setenv(env_var, env_value)
config = build_config(server="$MT5_SERVER", allow_whole_dollar_env=True)
config = build_config(**{field: f"${env_var}"}, allow_whole_dollar_env=True) # type: ignore[arg-type]
assert config.server == "Broker-Demo"
def test_build_config_substitutes_password_with_opt_in(
self,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""build_config expands $ENV_NAME password when allow_whole_dollar_env=True."""
monkeypatch.setenv("MT5_PASSWORD", "secret")
config = build_config(password="$MT5_PASSWORD", allow_whole_dollar_env=True)
assert config.password == "secret" # noqa: S105
def test_build_config_substitutes_path_with_opt_in(
self,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test build_config expands $ENV_NAME path when allow_whole_dollar_env=True."""
monkeypatch.setenv("MT5_PATH", "/opt/mt5/terminal64.exe")
config = build_config(path="$MT5_PATH", allow_whole_dollar_env=True)
assert config.path == "/opt/mt5/terminal64.exe"
assert getattr(config, field) == env_value
def test_build_config_leaves_dollar_literal_by_default(
self,