3

I have written a test that tries to mock an exception as a side effect of a requests get operation. I am using the requests_mock library as shown in the code listing below:

def test_owm_client_raises_error_for_timeout_error(owm_proxy: OWMProxy) -> None:
  
      with requests_mock.Mocker() as m:
          m.get(
              "http://api.openweathermap.org/geo/1.0/direct/*",
              exc=request_exceptions.Timeout,
          )
  
          city = "london"
          utc_now = datetime.now(timezone.utc)
          target_time = int((utc_now + timedelta(hours=10)).timestamp())
  
          with pytest.raises(APIException):
              owm_proxy.for_time(city, datetime.fromtimestamp(target_time).isoformat())

Is it possible to mock a url using wildcard parameters, e.g. http://api.openweathermap.org/geo/1.0/direct/*? So far, the only way that I can simulate the desired effect of mocking a Timeout error is using requests.ANY as the url parameter in the mock.

anon_dcs3spp
  • 2,342
  • 2
  • 28
  • 62

1 Answers1

2

Create a regex pattern via re.compile() which you can input to the requests mocker as documented:

import re

import pytest
import requests
import requests_mock


def test_owm_client_raises_error_for_timeout_error():
      with requests_mock.Mocker() as m:
          # This is the regex pattern. Currently, it will accept any text after the base URL below. Update this if your requirements are stricter.
          matcher = re.compile('http://api.openweathermap.org/geo/1.0/direct/.*')

          # For simplicity, let's say we will just raise ValueError for the target URL
          m.get(
              matcher,
              exc=ValueError("Mocked error!"),
          )

          # Test if the exception ValueError will be raised if we accessed the target URLs
          with pytest.raises(ValueError):
            requests.get("http://api.openweathermap.org/geo/1.0/direct/")
          with pytest.raises(ValueError):
            requests.get("http://api.openweathermap.org/geo/1.0/direct/abcde")
          with pytest.raises(ValueError):
            requests.get("http://api.openweathermap.org/geo/1.0/direct/12345")
          with pytest.raises(ValueError):
            requests.get("http://api.openweathermap.org/geo/1.0/direct/abcde/12345")
          with pytest.raises(ValueError):
            requests.get("http://api.openweathermap.org/geo/1.0/direct/abcde/12345?any=thing&in=here")

          # Test if the mocked request wouldn't be used if the URL is different. Thus, the exception should show that the URL wasn't mocked.
          with pytest.raises(requests_mock.exceptions.NoMockAddress):
            requests.get("http://api.openweathermap.org/geo/1.0/direct2/")
          with pytest.raises(requests_mock.exceptions.NoMockAddress):
            requests.get("http://api.openweathermap.org/geo/1.0/direct2/abcde")

Output:

$ pytest -q
.
1 passed in 0.07s
  • Many thanks :) Test code runs locally, appreciated :) When I try to integrate it in my scenario I am receiving NoMockAddress error. So, my URL must not be getting mocked. I will have to do some trace debugging on requests library to determine correct URL being requested via pyowm library to geo API on openweathermap. Anyway, thanks again accepting your answer! – anon_dcs3spp Sep 15 '21 at 11:01