Skip to content

Testing: parametrize phantom-kwarg behavioral test across all Request models #219

Description

@TexasCoding

Summary

test_request_bodies_use_extra_forbid is parametrized over every Request model and asserts model_config['extra'] == 'forbid' — but that's a config-level assertion, not behavioral. The actual behavioral assertion (constructing the model with a phantom kwarg raises ValidationError) is only spot-checked for CreateOrderRequest (test_forbid_extra_rejects_unknown_kwarg).

For all other request models (AmendOrderRequest, DecreaseOrderRequest, BatchCreate*, CreateOrderGroupRequest, UpdateOrderGroupLimitRequest, CreateRFQRequest, CreateQuoteRequest, AcceptQuoteRequest, ApplySubaccountTransferRequest, UpdateSubaccountNettingRequest, CreateApiKeyRequest, GenerateApiKeyRequest, all V2 order request models, etc.), there is no test that constructs the model with a phantom field and asserts ValidationError.

A model that accidentally sets extra='allow' AND has a typo in a field name would slip both gates: the config test catches the first miss, but if a contributor changes the config they may also re-add the field name with a typo elsewhere, and the per-model phantom test would catch only the second miss.

Location

  • tests/test_model_extra_policy.py:60-69 — config-level only
  • tests/test_orders.py / tests/test_async_orders.pyCreateOrderRequest-only spot check
  • tests/test_models.py:903CreateOrderRequest-only

Recommended fix

Add a single parametrized behavioral test that iterates the existing _REQUEST_MODELS collection, instantiates each model with minimal valid required kwargs plus ghost_field='x', and asserts pydantic.ValidationError:

import pytest
from pydantic import ValidationError

@pytest.mark.parametrize("model_cls", _REQUEST_MODELS, ids=lambda c: c.__name__)
def test_request_model_rejects_phantom_field(model_cls, minimal_kwargs):
    valid = minimal_kwargs(model_cls)
    with pytest.raises(ValidationError) as exc:
        model_cls(**valid, ghost_field="x")
    assert any(err["type"] == "extra_forbidden" for err in exc.value.errors())

minimal_kwargs(model_cls) can use model_cls.model_fields to compute required kwargs from defaults / annotations, or maintain a small fixture map for the ones that can't be auto-derived.

This pairs with the existing config check and pins behavior in addition to configuration.

Severity & category

medium / testing

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions