2

I am creating a parameterized Mock PyTest to test API behaviors. I am trying to simplify the test code by testing the instance modified behavior, e.g. throw and exception, and the default behavior, i.e. load JSON from file vs. calling REST API.

I do not know how to add an array entry to represent the "default" mock behavior?

@pytest.mark.parametrize(
    ("get_nearby_sensors_mock", "get_nearby_sensors_errors"),
    [
        (AsyncMock(side_effect=Exception), {CONF_BASE: CONF_UNKNOWN}),
        (AsyncMock(side_effect=PurpleAirError), {CONF_BASE: CONF_UNKNOWN}),
        (AsyncMock(side_effect=InvalidApiKeyError), {CONF_BASE: CONF_INVALID_API_KEY}),
        (AsyncMock(return_value=[]), {CONF_BASE: CONF_NO_SENSORS_FOUND}),
        # What do I do here?
        # (AsyncMock(api.sensors, "async_get_nearby_sensors")) does not work as api is not in scope?
        # (AsyncMock(side_effect=None), {}) does not call the default fixture?
        (AsyncMock(), {}),
    ],
)
async def test_validate_coordinates(
    hass: HomeAssistant,
    mock_aiopurpleair,
    api,
    get_nearby_sensors_mock,
    get_nearby_sensors_errors,
) -> None:
    """Test validate_coordinates errors."""

    with (
        patch.object(api, "async_check_api_key"),
        patch.object(api.sensors, "async_get_nearby_sensors", get_nearby_sensors_mock),
    ):
        result: ConfigValidation = await ConfigValidation.async_validate_coordinates(
            hass, TEST_API_KEY, TEST_LATITUDE, TEST_LONGITUDE, TEST_RADIUS
        )
        assert result.errors == get_nearby_sensors_errors
        if result.errors == {}:
            assert result.data is not None
        else:
            assert result.data is None

How do I add a parameter for the "default behavior" of patch.object(api.sensors, "async_get_nearby_sensors") that will use the fixture to load data from canned JSON file?

Why mock; async_validate_coordinates() calls async_check_api_key() that needs to be mocked to pass, and async_get_nearby_sensors() that is mocked with a fixture to return data from a JSON file.

For ref this is the conftest.py file.

2
  • Do you want to make a real call to async_get_nearby_sensors? Commented Mar 10 at 13:32
  • I want the parametrize entry to call the mocked version that reads from JSON file, similar to if I had used just patch.object(api.sensors, "async_get_nearby_sensors") that loads from JSON. Commented Mar 10 at 13:58

1 Answer 1

0

As a workaround, you could deal with any api-related case inside the function, where the api is known.
For this single-use, I would use None to trigger the default case

@pytest.mark.parametrize(
    ("get_nearby_sensors_mock", "get_nearby_sensors_errors"),
    [
        # [...]
        (None, {}),
    ],
)
async def test_validate_coordinates(
    hass: HomeAssistant,
    mock_aiopurpleair,
    api,
    get_nearby_sensors_mock,
    get_nearby_sensors_errors,
) -> None:
    """Test validate_coordinates errors."""
    if get_nearby_sensors_mock is None:
        get_nearby_sensors_mock = AsyncMock(api.sensors, "async_get_nearby_sensors")

    with (patch.object( # [...]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.