我正在为使用库http.Client的项目创建一个API类
问题在于单元测试,当我试图引发错误并使用assertRaises进行测试时,assertRaises即使在引发正确异常的情况下也会失败
我有一个模块“Foo”
+---Foo
¦ __init__.py
¦ api.py
在我的\uuu init\uuu.py中,只有我的异常类和装饰器
import errno
import json
import os
import signal
from dataclasses import dataclass
from functools import wraps
from http.client import HTTPMessage, HTTPException
from typing import Optional
@dataclass
class APIResponse:
method: str
code: int
reason: str
length: Optional[int]
headers: HTTPMessage
message: HTTPMessage
@dataclass
class Token:
access_token: str
expires_in: int
token_type: str
@dataclass
class ClientCredentials:
client_id: str
client_secret: str
audience: str
grant_type: str = "client_credentials"
class ClientCredentialsEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ClientCredentials):
return o.__dict__
return json.JSONEncoder.default(self, o)
class AuthenticationError(HTTPException):
pass
def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return wraps(func)(wrapper)
return decorator
py包含我的api类,我正在测试该类的身份验证方法以获取访问令牌
import http.client
import json
import logging
from Foo import ClientCredentials, Token, ClientCredentialsEncoder, AuthenticationError, timeout
from settings import config, API_HOST, AUTH_DOMAIN
class API:
def __init__(self, auth0_domain, client_credentials: ClientCredentials):
self.auth0_domain: str = auth0_domain
self.client_credentials = client_credentials
self._session = http.client.HTTPSConnection(self.auth0_domain)
self.token: Token = self.authenticate()
@property
def session(self):
return self._session
@timeout(10, "API Takes too long to respond.")
def api_request(self, method: str, url: str, body: str, headers: dict):
logging.debug(f"Senging {method} request to {url} for data: {body}...")
self.session.request(method=method, url=url, body=body, headers=headers)
res = self.session.getresponse()
return res
def authenticate(self) -> Token:
logging.debug("Getting API authentiation...")
method = "POST"
url = "/oauth/token"
body = json.dumps(
obj=self.client_credentials,
cls=ClientCredentialsEncoder
)
headers = {'content-type': "application/json"}
response = self.api_request(method=method, url=url, body=body, headers=headers)
status = response.status
reason = response.reason
data = response.read()
json_dict = json.loads(data)
self._session.close()
if status == 403:
logging.error(f"Error {status}: {reason}. Authentication fail.")
raise AuthenticationError(
f"Invalid Credentials. Error: '{json_dict['error']}', Description: {json_dict['error_description']}"
)
if status == 401:
logging.error(f"Error {status}: {reason}. Authentication fail.")
raise AuthenticationError(
f"Invalid Credentials. Error: '{json_dict['error']}', Description: {json_dict['error_description']}"
)
logging.info(f"Response {status}. Authentication successful!")
return Token(
access_token=json_dict['access_token'],
expires_in=json_dict['expires_in'],
token_type=json_dict['token_type'],
)
现在,我正在尝试测试我的身份验证,如果它获得了无效的凭据,它是否会引发正确的错误。 这是我的测试脚本
import logging
import unittest
from typing import Tuple
from Foo import ClientCredentials, Token, AuthenticationError
from Foo.api import API
from settings import config, API_HOST
class MyTestCase(unittest.TestCase):
def setUp(self):
pass
def test_token(self):
api = API(*self.good_credentials)
self.assertIsInstance(api.authenticate(), Token)
def test_invalid_credentials(self):
api = API(*self.invalid_credentials)
# self.assertRaises(AuthenticationError, api.authenticate)
with self.assertRaises(AuthenticationError) as error_msg:
api.authenticate()
self.assertEqual(error_msg, "Invalid Credentials. Error: 'access_denied', Description: Unauthorized")
@unittest.skip("Can't get the right assertRaises")
def test_invalid_auth_domain(self):
api = API(*self.invalid_auth_domain)
with self.assertRaises(TimeoutError) as e:
api.authenticate()
self.assertEqual(e, "API Takes too long to respond.")
# self.assertRaises(TimeoutError, api2.authenticate())
@property
def good_credentials(self) -> Tuple[str, ClientCredentials]:
auth0_domain = "my.auth.domain"
credentials = ClientCredentials(
client_id=config.read_param('api.value.client-id'),
# client_id='aw;oieja;wlejf',
client_secret=config.read_param('api.value.client-secret'),
audience=API_HOST,
)
return auth0_domain, credentials
@property
def invalid_auth_domain(self) -> Tuple[str, ClientCredentials]:
auth0_domain = "my.auth.domain"
credentials = ClientCredentials(
client_id=config.read_param('api.value.client-id'),
client_secret=config.read_param('api.value.client-secret'),
audience=API_HOST,
)
return auth0_domain, credentials
@property
def invalid_credentials(self) -> Tuple[str, ClientCredentials]:
auth0_domain = "my.auth.domain"
credentials = ClientCredentials(
# client_id=config.read_param('api.value.client-id'),
client_id='aw;oieja;wlejf',
client_secret=config.read_param('api.value.client-secret'),
audience=API_HOST,
)
return auth0_domain, credentials
if __name__ == '__main__':
unittest.main()
正如您在我的测试中所看到的,我为assertRaises尝试了两种方法:
# Trial 1
with self.assertRaises(AuthenticationError) as e:
api.authenticate()
self.assertEqual(error_msg, "Invalid Credentials. Error: 'access_denied', Description: Unauthorized")
# Trial 2
self.assertRaises(AuthenticationError, api.authenticate)
即使引发了正确的异常,assertRaises也会失败。 以下是我在运行unittest后从terminal获得的日志:
Ran 3 tests in 0.842s
FAILED (errors=1, skipped=1)
Error
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor
yield
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 615, in run
testMethod()
File "/Users/pluggle/Documents/Gitlab/Laveness/onboarding/test/api_authentication_test.py", line 22, in test_invalid_credentials
api = API(*self.invalid_credentials)
File "/Users/pluggle/Documents/Gitlab/Laveness/onboarding/Foo/api.py", line 17, in __init__
self.token: Token = self.authenticate()
File "/Users/pluggle/Documents/Gitlab/Laveness/onboarding/Foo/api.py", line 66, in authenticate
f"Invalid Credentials. Error: '{json_dict['error']}', Description: {json_dict['error_description']}"
Foo.AuthenticationError: Invalid Credentials. Error: 'access_denied', Description: Unauthorized
Assertion failed
Assertion failed
Process finished with exit code 1
Assertion failed
Assertion failed
从这个问题:AssertRaises fails even though exception is raised
他似乎和我有同样的问题,但他是从两个不同的路径导入错误的,其中对我来说,我非常确定我的异常是从我的Foo包上的\uuuu init\uuuuuuuuuuy.py导入的
真希望有人能帮我。我真的觉得这里有些东西我忽略了
非常感谢
如果您读取stacktrace,它将在此行上上升:
它是
assertRaises
前面的一行,因此不会被它捕获这是因为
API.__init__
本身调用self.authenticate()
相关问题 更多 >
编程相关推荐