#python #unit-testing #mocking
#python #модульное тестирование #издевательство
Вопрос:
Я пытаюсь выполнить модульное тестирование метода класса, который выполняет запрос API и возвращает файл json, который загружается в переменную в качестве словаря. Запрос возвращает файл json в соответствии с запросом. Еще один тест, который я хотел бы реализовать, заключается в том, что он обращается к правильной ссылке. Я использую patch в качестве диспетчера контекста с макетным модулем.
В общем, мое приложение snowReport.py обращается к API погоды, который возвращает weatherJson, а затем обращается к этому Json, чтобы определить, будет ли снег в прогнозе. Класс называется Resort, потому что он предназначен специально для горнолыжных курортов.
В моем модуле это моя __init__
функция.
class Resort():
# kwargs is created so the user can pass in "96hr", "realtime", and or "360min"
def __init__(self, resortKey, *args):
# Check if you are in the current directory, if not, set it to the current directory
currentDir = os.getcwd()
if currentDir != D_NAME:
os.chdir(D_NAME)
else:
pass
# Checks if the user enters arguments to initiate json files or not
self.dataJSON = SKI_RESORT_JSON
self.args = args
if not args:
raise Exception("Invalid arg passed. Function arguments must contain one of '360min' and/or '96hr' and/or 'realtime'") # Note there is a hidden arg that is called test that does not access the api to do a mock test
# Opens json file to get location parameters
with open(SKI_RESORT_JSON, "r") as f:
resortDictList = json.load(f)
resortDict = resortDictList[resortKey]
self.name = resortDict["name"]
self.lon = resortDict["lon"]
self.lat = resortDict["lat"]
self.country = resortDict["country"]
self.weatherJsonRealTime = {}
self.weatherJson360Min = {}
self.weatherJson96hr = {}
Цель этой __init_
функции _ — инициализировать переменные и получить доступ к файлу .json, где он извлекает данные о местоположении.
Функция, которую я пытаюсь протестировать, представляет собой метод класса, который выглядит следующим образом:
def requestRealtime(self):
querystring = {
"lat": str(self.lat),
"lon": str(self.lon),
"unit_system": "si",
"fields": "precipitation,precipitation_type,temp,feels_like,wind_speed,wind_direction,sunrise,sunset,visibility,cloud_cover,cloud_base,weather_code",
"apikey": CLIMACELL_KEY,
}
response = requests.request("GET", URL_REALTIME, params=querystring)
if response.ok:
self.weatherJsonRealTime = json.load(response.text)
else:
return "Bad response"
self.nowTime = localTime(self.weatherJsonRealTime["observation_time"]["value"])
self.nowTemp = self.weatherJsonRealTime["temp"]["value"]
self.nowFeelsLike = self.weatherJsonRealTime["feels_like"]["value"]
self.nowPrecipitation = self.weatherJsonRealTime["precipitation"]["value"]
self.nowPrecipitationType = self.weatherJsonRealTime["precipitation_type"]["value"]
self.nowWindSpeed = self.weatherJsonRealTime["wind_speed"]["value"]
self.nowWindDirection = self.weatherJsonRealTime["wind_direction"]["value"]
self.nowCloudCover = self.weatherJsonRealTime["cloud_cover"]["value"]
return self.weatherJsonRealTime
Я пытаюсь протестировать запрос, точнее, я пытаюсь протестировать этот запрос. Для этого я использую диспетчер контекста исправлений, чтобы имитировать request.requests и установить возвращаемое значение в качестве статического тестового файла json. Мой тестовый код выглядит следующим образом:
with open(".\Resources\test_realtimeJson.json", "r") as f:
testrealtimeDict = json.load(f)
@classmethod
def setUpClass(cls):
cls.testResort = snowReport.Resort("test_Location (Banff)", "96hr", "realtime", "360min")
os.chdir(D_NAME) # Set the directory back to D_NAME because that the snowReport.Resort class changes it's class
def test_requestRealtime(self):
with patch("snowApp.snowReport.requests.request") as mocked_request:
mocked_request.return_value.ok = True
mocked_request.return_value.request = testrealtimeDict
self.testResort.requestRealtime()
Предполагая, что макет работает, я хотел бы затем использовать функцию assertEqual для тестирования и проверки того, возвращают ли атрибуты, созданные в функции snowReport, ожидаемое значение на основе словаря, который я ему передаю.
Когда я запускаю тестовый скрипт, он выдает мне ошибку:
File "c:userssteveappdatalocalprogramspythonpython39libjson__init__.py", line 339, in loads
raise TypeError(f'the JSON object must be str, bytes or bytearray, '
TypeError: the JSON object must be str, bytes or bytearray, not MagicMock
Поскольку я имитирую запрос и устанавливаю возвращаемое значение для созданного мной testrealtimeDict, не следует ли self.weatherJsonRealtime = testrealtimeDict ? Почему он выдает ошибку типа? Также — подходит ли модульный тест, который я планирую, для этого приложения или есть лучший или более простой способ выполнить это?