I am writing a python module to interact to the ROD (remedy on demand) BMC ticketing product. So far I have only written the log in and log out methods and tests. Before I crack on with the more complex methods I hope someone can review the current test strategy and happy to hear any suggestions for improvements.
rodAPI.py
import requests
class RodApi:
def __init__(self, fqdn, username, password, token_type="AR-JWT"):
self.username = username
self.password = password
self.fqdn = fqdn
self.token_type = token_type
self.login_url = f"https://{fqdn}/api/jwt/login"
self.logout_url = f"https://{fqdn}/api/jwt/logout"
self.token = None
def login(self) -> bool:
data = {"username": self.username, "password": self.password}
headers = {"content-type": "application/x-www-form-urlencoded"}
response = requests.post(self.login_url, data=data, headers=headers)
print(f"connecting to URL: {self.login_url}")
print(f"https status code: {response.status_code}")
self.token = response.text
if response.status_code == 200:
return True
return False
def logout(self) -> bool:
headers = {"Authorization": f"{self.token_type} {self.token}"}
response = requests.post(self.logout_url, headers=headers)
print(f"connecting to URL: {self.logout_url}")
print(f"https status code: {response.status_code}")
if response.status_code == 204:
print(f"Logged out with a status of: {response.status_code}")
return True
else:
print(f"Error logging out: {response.text}")
return False
test_rodAPI
import pytest
from rodAPI import RodApi
@pytest.fixture()
def rod_api_instance():
rod_api = RodApi("example.com", "some_user", "some_password")
return rod_api
@pytest.fixture()
def rod_api_logged_in_instance(responses, rod_api_instance):
responses.add(responses.POST, rod_api_instance.login_url, body="some_token_string")
rod_api_instance.login()
return rod_api_instance
def test_login_success(responses, rod_api_instance: RodApi):
responses.add(responses.POST, rod_api_instance.login_url, body="some_token_string")
result = rod_api_instance.login()
assert result is True
assert rod_api_instance.token == "some_token_string"
def test_login_fail(responses, rod_api_instance: RodApi):
responses.add(responses.POST, rod_api_instance.login_url, status=404)
result = rod_api_instance.login()
assert result is False
def test_logout_success(responses, rod_api_logged_in_instance: RodApi):
responses.add(responses.POST, rod_api_logged_in_instance.logout_url, status=204)
result = rod_api_logged_in_instance.logout()
assert result is True
def test_logout_fail(responses, rod_api_logged_in_instance: RodApi):
responses.add(responses.POST, rod_api_logged_in_instance.logout_url, status=404)
result = rod_api_logged_in_instance.logout()
assert result is False
```
1 Answer 1
Redundant headers
Read https://github.com/psf/requests/blob/master/requests/models.py#L514 - your use of
headers = {"content-type": "application/x-www-form-urlencoded"}
should not be needed.
Out-of-order progress
You print
print(f"connecting to URL: {self.login_url}")
when this has already happened. Either say "connected to", or move this statement before your post
.
Exception degradation
Resist the urge to sabotage the Python exception system. Rather than returning booleans from your methods, call response.raise_for_status
, and optionally wrap that in a try/except/raise MyException() from e
with your own exception type. raise_for_status
will also obviate your status code checks.
-
1\$\begingroup\$ Thanks for the feedback, I wasnt aware of raise for status, I have taken all your feedback and incorporated it into my code and testing strategy. \$\endgroup\$Chris Doyle– Chris Doyle2021年01月01日 20:59:39 +00:00Commented Jan 1, 2021 at 20:59