Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using nested mocks - URL's from parent Mock not available in child Mock #645

Closed
bblommers opened this issue Jun 22, 2023 · 4 comments
Closed
Assignees

Comments

@bblommers
Copy link
Contributor

Describe the bug

Hi team!

I have a scenario where I start a RequestsMock, and then start another while the first one is still active.
Mocked URL's from the first (parent) mock are not available in the child mock.

Is this a bug, or a side-effect of how the library is setup?

Additional context

No response

Version of responses

0.22.0

Steps to Reproduce

def test_nested_mocks():
    url_1 = "http://google.com"
    a = responses.RequestsMock()
    a.start()
    a.add(responses.GET, url_1, json={"foo": "bar_a"})

    b = responses.RequestsMock()
    b.start()

    # This call fails when b is active
    # if `b.start()` is commented out, it does work
    assert requests.get(url_1).json() == {"foo": "bar_a"}

    b.stop()

    assert requests.get(url_1).json() == {"foo": "bar_a"}
    a.stop()

Expected Result

Test passes

Actual Result

An error message:
Connection refused by Responses - the call doesn't match any registered mock.

@beliaev-maksim
Copy link
Collaborator

@bblommers
I think we solved similar issue in the past

in this case it is nested decorator. You register response per decorator, then upper decorator has mock registered, while second does not have.

for example this code will break again, because now A is lacking registered mock

def test_nested_mocks():
    url_1 = "http://google.com"
    a = responses.RequestsMock()
    a.start()

    b = responses.RequestsMock()
    b.start()
    b.add(responses.GET, url_1, json={"foo": "bar_a"})

    # This call fails when b is active
    # if `b.start()` is commented out, it does work
    assert requests.get(url_1).json() == {"foo": "bar_a"}

    b.stop()

    assert requests.get(url_1).json() == {"foo": "bar_a"}
    a.stop()

@bblommers
Copy link
Contributor Author

The example I posted is simplified - the actual use case is that a user starts the first mock, and a third-party library (Moto) starts the second mock.

So when starting the second mock, we don't actually know whether the first mock exists, what URL's are registered, etc.

@beliaev-maksim
Copy link
Collaborator

@bblommers
let me give insight how responses works and we can think what we can do for Moto

the difference from standard mocks is that we do not expose any adapter or session to outside. In background we patch requests adapter and override send request (basically we intercept it)

that means, that when you do requests.get(url_1) you do not do responses.request.get(), it is actual requests.get(url_1). I try to give an idea that when we are called in responses, we do not know about other mock. We just see whatever registered in out context loop and try to reuse it, there is no reference from requests to a particular instance of the mock

what are users try to achieve ?

can we educate users who want to use both responses and moto to follow only this concept:

def test_nested_mocks():
    url_1 = "http://google.com"

    b = responses.RequestsMock()
    b.start()
    b.add(responses.GET, url_1, json={"foo": "bar_b"})

    with responses.RequestsMock() as a:
        a.add(responses.GET, url_1, json={"foo": "bar_a"})
        assert requests.get(url_1).json() == {"foo": "bar_a"}

    assert requests.get(url_1).json() == {"foo": "bar_b"}
    b.stop()

@beliaev-maksim
Copy link
Collaborator

solved in "moto" thread based on PR #648

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

3 participants