anyone know why this error is happening? i've been running the same line for my other tests and only this one is returning an error
both lines in test_coverageReturnSuccess + test_coverageReturnCorrectCoverage returning this error:
response.render()
AttributeError: 'HttpResponse' object has no attribute 'render'
This is my APi test case
class CoverageTest(APITestCase):
protein = None
domain = None
protein_domain = None
good_url = ''
bad_url = ''
def setUp(self):
self.protein = ProteinFactory.create(pk=1, protein_id='A0A014PQC0', length=338)
self.domain = PfamFactory.create()
self.protein_domain = ProteinDomainLinkFactory.create(protein=self.protein,
pfam_id=self.domain,
start=157,
stop=314)
# Set urls
self.good_url = reverse('coverage', kwargs={'protein_id': 'A0A014PQC0'})
def tearDown(self):
# Reset test tables
Protein.objects.all().delete()
Pfam.objects.all().delete()
ProteinDomainLink.objects.all().delete()
# Reset primary keys
ProteinFactory.reset_sequence(0)
PfamFactory.reset_sequence(0)
ProteinDomainLinkFactory.reset_sequence(0)
def test_coverageReturnSuccess(self):
"""
Ensure we get an 200 OK status code when making a valid GET request.
"""
response = self.client.get(self.good_url, format='json')
response.render()
self.assertEqual(response.status_code, 200)
def test_coverageReturnCorrectCoverage(self):
"""
Ensure we get the right coverage of the requested protein
"""
response = self.client.get(self.good_url, format='json')
response.render()
data = json.loads(response.content)
self.assertEqual(data, 0.46449704142011833)
You should not render the response, the response is already rendered, so for example:
def test_coverageReturnSuccess(self):
"""
Ensure we get an 200 OK status code when making a valid GET request.
"""
response = self.client.get(self.good_url, format='json')
# not response.render()!
self.assertEqual(response.status_code, 200)
For JSON, you use:
def test_coverageReturnCorrectCoverage(self):
"""
Ensure we get the right coverage of the requested protein
"""
response = self.client.get(self.good_url, format='json')
# not response.render()!
data = response.json()
self.assertEqual(data, 0.46449704142011833)
Related
My function that I am trying to test is returning list of strings:
def listForumsIds:
response = requests.get(url)
forums= response.json().get('forums')
forumsIds= [forum['documentId'] for forum in forums]
# return like: ['id1', 'id2', 'id3'.....]
return forumsIds
My test function:
#requests_mock.mock()
def test_forms(self, m):
# I also used json='response'
m.get('valid url', text="response", status_code=200)
resp = listForumsIds('valid url')
# ERROR !!!!
assert resp == "response"
I am getting error like: json.decoder.JSONDecodeError or str object has no attribute get
How to fake my response to be match return value of my function?
You have to pass the desired payload in the json field of the mocked response. Example, adapted to your code:
class MyTests(unittest.TestCase):
#requests_mock.mock()
def test_forms(self, m):
payload = {"forums": [{"documentId": "id1"}]}
m.register_uri("GET", "https://www.example.com", json=payload)
ids = listForumsIds('https://www.example.com')
assert ids == ['id1']
I am trying to pass my session object from one class to another. But I am not sure whats happening.
class CreateSession:
def __init__(self, user, pwd, url="http://url_to_hit"):
self.url = url
self.user = user
self.pwd = pwd
def get_session(self):
sess = requests.Session()
r = sess.get(self.url + "/", auth=(self.user, self.pwd))
print(r.content)
return sess
class TestGet(CreateSession):
def get_response(self):
s = self.get_session()
print(s)
data = s.get(self.url + '/some-get')
print(data.status_code)
print(data)
if __name__ == "__main__":
TestGet(user='user', pwd='pwd').get_response()
I am getting 401 for get_response(). Not able to understand this.
What's a 401?
The response you're getting means that you're unauthorised to access the resource.
A session is used in order to persist headers and other prerequisites throughout requests, why are you creating the session every time rather than storing it in a variable?
As is, the session should work the only issue is that you're trying to call a resource that you don't have access to. - You're not passing the url parameter either in the initialisation.
Example of how you can effectively use Session:
from requests import Session
from requests.exceptions import HTTPError
class TestGet:
__session = None
__username = None
__password = None
def __init__(self, username, password):
self.__username = username
self.__password = password
#property
def session(self):
if self.__session is None:
self.__session = Session()
self.__session.auth = (self.__user, self.__pwd)
return self.__session
#session.setter
def session(self, value):
raise AttributeError('Setting \'session\' attribute is prohibited.')
def get_response(self, url):
try:
response = self.session.get(url)
# raises if the status code is an error - 4xx, 5xx
response.raise_for_status()
return response
except HTTPError as e:
# you received an http error .. handle it here (e contains the request and response)
pass
test_get = TestGet('my_user', 'my_pass')
first_response = test_get.get_response('http://your-website-with-basic-auth.com')
second_response = test_get.get_response('http://another-url.com')
my_session = test_get.session
my_session.get('http://url.com')
I have following code:
class StackOverflowHandler(tornado.web.RequestHandler):
def get(self, look_up_pattern):
url = "https://api.stackexchange.com/2.2/search?order=desc&sort=votes&intitle=%s&site=stackoverflow"
response = self.async_get(url)
print(response)
self.write(response)
#gen.coroutine
def async_get(self, url):
link = httpclient.AsyncHTTPClient()
request = httpclient.HTTPRequest(url)
response = yield link.fetch(request)
data = response.body.decode('utf-8')
data = json.loads(data)
return data
application = tornado.web.Application([
(r"/search/(.*)", StackOverflowHandler),
])
The type that returns from async_get is tornado.concurrent.Future.
The exception is:
TypeError: write() only accepts bytes, unicode, and dict objects
I am new to asynchronous programming, please point me out my mistake.
Since async_get is coroutine it returns Future object. To get "real" results, Future must be resolved - it need to be yielded. More over the get handler must be decorated as asynchronous as well
class StackOverflowHandler(tornado.web.RequestHandler):
#gen.coroutine
def get(self, look_up_pattern):
url = "https://api.stackexchange.com/2.2/search?order=desc&sort=votes&intitle=%s&site=stackoverflow"
response = yield self.async_get(url)
print(response)
self.write(response)
#gen.coroutine
def async_get(self, url):
link = httpclient.AsyncHTTPClient()
request = httpclient.HTTPRequest(url)
response = yield link.fetch(request)
data = response.body.decode('utf-8')
data = json.loads(data)
return data
Hi!
I have a route that I have protected using HTTP Basic authentication, which is implemented by Flask-HTTPAuth. Everything works fine (i can access the route) if i use curl, but when unit testing, the route can't be accessed, even though i provide it with the right username and password.
Here are the relevant code snippets in my testing module:
class TestClient(object):
def __init__(self, app):
self.client = app.test_client()
def send(self, url, method, data=None, headers={}):
if data:
data = json.dumps(data)
rv = method(url, data=data, headers=headers)
return rv, json.loads(rv.data.decode('utf-8'))
def delete(self, url, headers={}):
return self.send(url, self.client.delete, headers)
class TestCase(unittest.TestCase):
def setUp(self):
app.config.from_object('test_config')
self.app = app
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
self.client = TestClient(self.app)
def test_delete_user(self):
# create new user
data = {'username': 'john', 'password': 'doe'}
self.client.post('/users', data=data)
# delete previously created user
headers = {}
headers['Authorization'] = 'Basic ' + b64encode((data['username'] + ':' + data['password'])
.encode('utf-8')).decode('utf-8')
headers['Content-Type'] = 'application/json'
headers['Accept'] = 'application/json'
rv, json = self.client.delete('/users', headers=headers)
self.assertTrue(rv.status_code == 200) # Returns 401 instead
Here are the callback methods required by Flask-HTTPAuth:
auth = HTTPBasicAuth()
#auth.verify_password
def verify_password(username, password):
# THIS METHOD NEVER GETS CALLED
user = User.query.filter_by(username=username).first()
if not user or not user.verify_password(password):
return False
g.user = user
return True
#auth.error_handler
def unauthorized():
response = jsonify({'status': 401, 'error': 'unauthorized', 'message': 'Please authenticate to access this API.'})
response.status_code = 401
return response
Any my route:
#app.route('/users', methods=['DELETE'])
#auth.login_required
def delete_user():
db.session.delete(g.user)
db.session.commit()
return jsonify({})
The unit test throws the following exception:
Traceback (most recent call last):
File "test_api.py", line 89, in test_delete_user
self.assertTrue(rv.status_code == 200) # Returns 401 instead
AssertionError: False is not true
I want to emphazise once more that everything works fine when i run curl with exactly the same arguments i provide for my test client, but when i run the test, verify_password method doesn't even get called.
Thank you very much for your help!
Here is an example how this could be done with pytest and the inbuilt monkeypatch fixture.
If I have this API function in some_flask_app:
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__)
auth = HTTPBasicAuth()
#app.route('/api/v1/version')
#auth.login_required
def api_get_version():
return jsonify({'version': get_version()})
I can create a fixture that returns a flask test client and patches the authenticate function in HTTPBasicAuth to always return True:
import pytest
from some_flask_app import app, auth
#pytest.fixture(name='client')
def initialize_authorized_test_client(monkeypatch):
app.testing = True
client = app.test_client()
monkeypatch.setattr(auth, 'authenticate', lambda x, y: True)
yield client
app.testing = False
def test_settings_tracking(client):
r = client.get("/api/v1/version")
assert r.status_code == 200
You are going to love this.
Your send method:
def send(self, url, method, data=None, headers={}):
pass
Your delete method:
def delete(self, url, headers={}):
return self.send(url, self.client.delete, headers)
Note you are passing headers as third positional argument, so it's going as data into send().
I have this strange problem with my view which is returning response in json format.My view looks like this:
def CheckPlayer(request,client_id):
if request.method == 'GET':
try:
user = User.objects.get(id = client_id)
except:
return Error(message = "User doesnot exists.")
message = request.GET.get('message','')
if not message:
return Error(message = "Argument Missing.")
response = {}
result = MakingRequest(message)
result = json.loads(result)
if result['failure'] == '0':
response['failure'] = '0'
else:
response['failure'] = '1'
return HttpResponse(json.dumps(response), mimetype="application/javascript")
else:
return Error()
def MakingRequest(message):
values = {'message':message}
rObjects = Ram.objects.all()
temp = []
for i in rObjects:
temp.append(i.appId)
values['registration_ids'] = temp
param = json.dumps(values)
req = urllib2.Request("https://android.googleapis.com/gcm/send", param)
req.add_header( 'Content-Type' , 'application/json' )
req.add_header( 'Authorization' , 'key=7FcEMnl0FRTSBjhfjfhjfHi1Rmg04Ns' )
response = urllib2.urlopen(req)
return response.read()
I have tested it on my local server it works perfectly , but if I run it on my server (nginx,gunicorn,django-mongoDB,mongoDB) then it gives me this Error.I know about this error that if a view doesnot return HttpResponse from a view then it djangi raises error "Nonetype object has no attribute csrf_exempt' " but in my case i am returning response which is in json format but still its giving me error.Please help me
You aren't returning an HttpResponse when you return Error(), so Django can't apply the decorator to it.