здесь указано, как вы можете улучшить код выше:
Сначала на конструкторе или init вам не нужны access_token, refresh_token и дата истечения срока действия. Чтобы упростить любые модули, использующие этот класс, все связанные с токенами вещи обрабатываются внутри OneDrive Class. Класс будет просто получать токен каждый раз, когда вы используете методы загрузки или загрузки. это удалит self._renew_token()
при любых других методах.
- Вы можете извлечь строку ниже:
request = Request(url, headers=headers)
with urlopen(request, timeout=self.timeout) as response:
Которая использовала несколько методов в своей собственной функции. это будет соответствовать одной ответственности, поэтому позже новый метод, называемый request
, будет отвечать за обработку HTTP-запроса, а другой метод, использующий этот метод, заботится только о возврате. С этим дизайном это также возможно позже в будущем, если вы решите изменить библиотеку на что-то другое, например Requests или AIOHTTP, вам нужно всего лишь изменить этот метод.
Для тестирования теперь вы можете использовать только методы
request
, исправив urllib, и теперь для
upload
или
download
есть несколько подходов, которые вы можете сделать, вы можете высмеять
request
или все же просто исправить urllib, который используется внутри метода запроса. Я рекомендую вам попробовать модульный тест (проверить все модули и смоделировать другой модуль, на который полагается этот модуль) и последующий интеграционный тест (все модули соединяются с другим модулем)
onedrive.py
import json
from datetime import datetime, timedelta
from urllib.request import Request, urlopen
TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
DRIVE_BY_ID_URL = "https://graph.microsoft.com/v1.0/drives/"
CLIENT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
class Onedrive:
def __init__(self):
access_token, refresh_token, expire_date = self._renew_token()
self._access_token = access_token
self._refresh_token = refresh_token
self._expire_date = expire_date
@staticmethod
def request(url, headers, method="GET", data=None):
"""
this function handle the actual HTTP request to actual endpoint
behind by providing url, headers, method and data
"""
request = Request(url, headers=headers, data=data, method=method)
with urlopen(request, timeout=5) as response:
return response
def download(self, drive_id, file_id, filename):
url = f"{DRIVE_BY_ID_URL}/{drive_id}/items/{file_id}/content?AVOverride=1"
with open(filename, "wb+") as fp:
headers = {"Authorization": self._access_token}
response = self.request(url, headers)
fp.write(response.read())
def upload(self, local_path, parent_drive_id, parent_id, filename):
url = f"{DRIVE_BY_ID_URL}/{parent_drive_id}/items/{parent_id}:/{filename}:/content"
headers = {
"Authorization": self._access_token,
"Content-Type": "application/octet-stream",
}
with open(local_path, "rb") as fp:
response = self.request(
url=url, headers=headers, data=fp.read(), method="PUT"
)
return json.load(response)
def _renew_token(self):
access_token = self._access_token
refresh_token = self._refresh_token
expire_date = self._expire_date
if self._expire_date <= datetime.now():
body = f"client_id={CLIENT_ID}&refresh_token={self._refresh_token}&grant_type=refresh_token"
access_token, refresh_token, expire_date = self._acquire_token(body)
return access_token, refresh_token, expire_date
def _acquire_token(self, body):
now = datetime.now()
response = self.request(
url=TOKEN_URL, headers=None, data=body.encode(), method="POST"
)
data = json.load(response)
access_token = data["access_token"]
refresh_token = data["refresh_token"]
expire = data["expires_in"]
expire_date = now + timedelta(seconds=int(expire))
return access_token, refresh_token, expire_date
test_onedrive.py
from unittest import TestCase
from unittest.mock import patch, MagicMock
from example import Onedrive
class TestOneDrive(TestCase):
@patch("urllib.request.urlopen")
def test_request(self, mock_urlopen):
mock = MagicMock()
mock.getcode.return_value = 200
mock.read.return_value = "some-contents"
mock.__enter__.return_value = mock
mock_urlopen.return_value = mock
response = Onedrive.request(
url="https://login.microsoftonline.com/common/oauth2/v2.0/token",
headers={"Content-Type": "application/x-www-form-urlencoded"},
method="POST",
data={"data": "some_data"},
)
self.assertEqual(response.getcode(), 200)
self.assertEqual(response.read(), "some-contents")
@patch("urllib.request.urlopen")
def test_download(self, mock_urlopen):
mock = MagicMock()
mock.getcode.return_value = 200
mock.read.return_value = "some-contents"
mock.__enter__.return_value = mock
mock_urlopen.return_value = mock
Onedrive().download(
drive_id="drive-id", file_id="file_id", filename="some_filename"
)
# now you just check whether the file actual written
ссылка: https://docs.python.org/3/howto/urllib2.html https://docs.python.org/3/library/unittest.mock.html