How mock requests exception using Pytest fixture for mock_requests? - pytest

So I was using the requests-mock library to mock the HTTP requests that I do with the requests library and everything went fine until I had to do a test to catch the exception.
Example of my function to be tested
def get_wordpress_installed_plugins(url: str, user: str, password: str) -> bytes:
try:
credentials = user + ':' + password
token = base64.b64encode(credentials.encode())
header = {'Authorization': 'Basic ' + token.decode('utf-8')}
response = requests.get(url, headers=header, verify=False)
response.raise_for_status()
except requests.exceptions.HTTPError as err:
logger.exception(f"Got response from {url} correctly with error {err}.")
raise CouldNotConnectWithApi(f"Problem retrieving information.")
logger.info(f"Got response from {url} correctly.")
return response.content
And the test to assert function did ok
#mock.patch("checkpluginsversion.logging.Logger.info")
def test_api_wordpress_list_plugins(logger_mock, requests_mock):
user = "user"
password = "password"
url = "https://www.example.com"
expected_result = b'[{"plugin": "akismet\\/akismet", "status": "active", "name": "Akismet Anti-Spam","version": "4.2.2"}]'
requests_mock.get(url,
content=b'[{"plugin": "akismet\\/akismet", "status": "active", "name": "Akismet Anti-Spam","version": "4.2.2"}]')
result = get_wordpress_installed_plugins(url, user, password)
assert result == expected_result
logger_mock.assert_called_with(f"Got response from {url} correctly.")
To be honest, I don't know if using pytest fixture mode of this library is the best way, but ok it is working for me. So the problem I have is when I have to test the function and raise the exception. Eventually, I did a workaround with #mock.patch, and worked for me.
#mock.patch("checkpluginsversion.requests.get")
#mock.patch("checkpluginsversion.logging.Logger.exception")
def test_api_should_return_an_exception(logger_mock,my_request_mock):
user = "user"
password = "password"
url = "https://www.example.com"
expected_result = b'[{"plugin": "akismet\\/akismet", "status": "active", "name": "Akismet Anti-Spam","version": "4.2.2"}]'
my_request_mock.side_effect = requests.exceptions.HTTPError
with pytest.raises(CouldNotConnectWithApi):
result = get_wordpress_installed_plugins(url, user, password)
#assert result == expected_result
logger_mock.assert_called_with(f"Got response from {url} correctly with error .")
But I would know and I will really appreciate it if someone could explain to me how to do a test to raise an exception using the pytest fixture of requests_mock library, thanks!

Related

How to Yahoo ads conversion tracker name through yahoo api

I want to change Yahoo ads conversion tracker name through API automatically.
But, when I run the following code, that returned an error.
access_token = XXXXXXXXXXXXX
account_id = XXXXXX
conversion_id = XXXXXXX
new_name = "new_name"
header = {"Content-Type": "application/json",\
"Accept": "application/json",\
"Authorization": "Bearer " + access_token}
url = "https://ads-search.yahooapis.jp/api/v8/ConversionTrackerService/set"
data = {'accountId':account_id, 'operand':[{'accountId': account_id, 'conversionTrackerId': conversion_id, "conversionTrackerName": new_name}]}
data = json.dumps(data).encode()
req = urllib.request.Request(url, data=data, method='POST', headers=header)
try:
with urllib.request.urlopen(req) as response:
body = json.loads(response.read())
headers = response.getheaders()
status = response.getcode()
print(headers)
print(status)
print(body)
except urllib.error.URLError as e:
print(e.reason)`
Retuened error is:
{'errors': [{'code': 'L0001', 'message': 'Lower list size.', 'details': [{'requestKey': 'operand', 'requestValue': None}]}], 'rid': '6fab0e1ac60dd2a871831484791976bf', 'rval': None}
I guess the length of "operand" field is 1 and it is right length according to yahoo api document. What I shuold do to fix this error?
I tryied to make length of "operand" field 2. But the result was same.

How do you post form data using pytest?

I'm trying to write a unit test that posts form data. The actual line in question is:
def test_create_request():
with app.test_client() as test_client:
app_url = '/requests/'
with app.app_context():
new_request = get_new_request()
form_data = json.dumps(new_request, default=str)
print('FORM DATA: ', form_data)
resp = test_client.post(app_url, data=form_data, headers={'Content-Type': 'application/json'})
assert resp.status_code == 200
s = json.loads(resp.data)
assert s['success'] == True
Where new_request is a dict representation of an object. The print statement yields (I've formatted it a bit):
FORM DATA: {
"request_id": "6",
"state_id": 1,
"orig_project_id": "1",
"orig_project_code": "QQQ",
"orig_allocated_funding": "123.45",
"orig_ytd_spend": "123.45",
"orig_ytd_commit": "123.45",
"orig_ytd_ocnr": "123.45",
"new_project_id": 2,
"new_funding_amount": 123.45,
"new_ytd_spend": 123.45,
"new_ytd_commit": 123.45,
"new_ytd_ocnr": 123.45,
"plan": "this is the plan",
"reason": "this is the reason",
"sm_director": "sm.dir#example.com",
"submitted_by": "xfgbn#vexample.com",
"created_on": "2021-09-14 16:32:55",
"meets_approval_guidelines": null
}
In the flask form, most fields are required. When I try to post the data, the form.validate_on_submit() function in the view's route returns False, and the 2nd assert fails. WTForms claims that none of the required orig_allocated_funding, orig_ytd_spend, orig_ytd_commit, orig_ytd_ocnr, new_project_id, new_funding_amount, new_ytd_spend, new_ytd_commit, new_ytd_ocnr, reason, plan, sm_director, or submitted_by fields are supplied.
I've read several tutorials, and I can't see what I'm doing wrong. Can anyone help?
What I was able to make work was scraping form_data altogether:
def test_create_request():
with app.test_client() as test_client:
app_url = '/requests/'
with app.app_context():
new_request = get_new_request()
resp = test_client.post(app_url, data=new_request)
assert resp.status_code == 200
s = json.loads(resp.data)
print(s['html'])
assert s['success'] == True

FastAPI pytest with arguments

I try to test fastAPI get route with pytest and the problem is how i can pass params to client.get
main.py
#app.get('/purpose'):
async def read_purpose(name, date):
"""some logic"""
return {'ok':'ok'}
test.py
client = TestClient(app)
def test_purpose():
response = client.get("/purpose", json={"name":"test_name", "date":"01.01.2020"})
assert response.status_code = 200
My test is failed. it can not find name, and date arguments.
How i can pass this arguments to my test.
Thank you
I have same problem when writing pytest for my first FastAPI demo.
#router.post('/item', tags=['items'], response_model=ShowItem)
async def create_item(item: ItemCreate,
user_id: int,
db: Session = Depends(get_db)):
date_posted = datetime.now().date()
# owner_id = 1
item = Items(**item.dict(),
date_posted=date_posted,
owner_id=user_id)
db.add(item)
db.commit()
db.refresh(item)
return item
You can try "params" instead of "json", because you are passing isolated query parameters
def test_create_item():
# wrong
data = {'title': 'Hot Boat', 'description': 'This is a boat', 'user_id': 1}
resp = client.post('/item', json.dumps(data))
# correct
data = {'title': 'Hot Boat', 'description': 'This is a boat'}
resp = client.post('/item', json.dumps(data), params={"user_id": 2})
assert resp.status_code == 200
Then i can by pass above error.
Try this fix:
client = TestClient(app)
def test_purpose():
response = client.get("/purpose", params={"name":"test_name", "date":"01.01.2020"})
assert response.status_code = 200
More detail refer Question 61383179

Misunderstood, an example from the documentation Pytest authorization

I decided to look at Pytest and immediately misunderstood, an example from the documentation, but there is no authorization, the test crashes with a code of 301, can anyone know what is the reason?
def test_with_authenticated_client(client, django_user_model):
username = "TestUser"
password = "1234567"
user = django_user_model.objects.create_user(username=username,
password=password)
# Use this:
client.force_login(user)
response = client.get('/new')
assert response.status_code == 200
def test_with_authenticated_client2(client):
username = "user2"
password = "bar"
# Or this:
client.login(username=username, password=password)
response = client.get('/new')
assert response.status_code == 200
with an unauthorized client, expected code 301
def test_make_not_authorized_user(client):
response = client.get('/new')
assert response.status_code in (302, 301)

Groovy script for Jenkins: execute HTTP request without 3rd party libraries

I need to create a Groovy post build script in Jenkins and I need to make a request without using any 3rd party libraries as those can't be referenced from Jenkins.
I tried something like this:
def connection = new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
URLEncoder.encode(
"select wind from weather.forecast where woeid in " + "(select woeid from geo.places(1) where text='chicago, il')",
'UTF-8' ) )
.openConnection() as HttpURLConnection
// set some headers
connection.setRequestProperty( 'User-Agent', 'groovy-2.4.4' )
connection.setRequestProperty( 'Accept', 'application/json' )
// get the response code - automatically sends the request
println connection.responseCode + ": " + connection.inputStream.text
but I also need to pass a JSON in the POST request and I'm not sure how I can do that. Any suggestion appreciated.
Executing POST request is pretty similar to a GET one, for example:
import groovy.json.JsonSlurper
// POST example
try {
def body = '{"id": 120}'
def http = new URL("http://localhost:8080/your/target/url").openConnection() as HttpURLConnection
http.setRequestMethod('POST')
http.setDoOutput(true)
http.setRequestProperty("Accept", 'application/json')
http.setRequestProperty("Content-Type", 'application/json')
http.outputStream.write(body.getBytes("UTF-8"))
http.connect()
def response = [:]
if (http.responseCode == 200) {
response = new JsonSlurper().parseText(http.inputStream.getText('UTF-8'))
} else {
response = new JsonSlurper().parseText(http.errorStream.getText('UTF-8'))
}
println "response: ${response}"
} catch (Exception e) {
// handle exception, e.g. Host unreachable, timeout etc.
}
There are two main differences comparing to GET request example:
You have to set HTTP method to POST
http.setRequestMethod('POST')
You write your POST body to outputStream:
http.outputStream.write(body.getBytes("UTF-8"))
where body might be a JSON represented as string:
def body = '{"id": 120}'
Eventually it's good practice to check what HTTP status code returned: in case of e.g. HTTP 200 OK you will get your response from inputStream while in case of any error like 404, 500 etc. you will get your error response body from errorStream.