Reputation: 6950
I'm writing a test to retrieve the top n posts from a community.
Before getting those values, I want to post data from a JSON file, instead of posting them to the endpoint individually.
I've tried slight variations of test_retrieve_recent_posts_existing_community
, but keep getting a TypeError
.
Can anyone suggest how I can fix the test case?
Route:
@app.route('/api/v2/post/retrieve/<community>/<top>', methods=['GET'])
def recent_community_posts(community=None, top=0):
community = request.args.get('community')
top = request.args.get('top')
filtered_posts = []
if community:
for post in posts:
if post['community'] == community:
filtered_posts.append(post)
if len(filtered_posts) == 0:
return {'message': 'Community does not exist ...', 'status': 402}
return {'data': jsonify(filtered_posts[:top]), 'message': "Filtered data based on community", 'status': 203}
Test:
def test_retrieve_recent_posts_existing_community(client):
with open('posts.json') as posts_data:
posts_json = json.dumps(posts_data)
client.post('/api/v2/post/create', data=json.dump(posts_json), content_type='application/json')
response = client.get('/api/v2/post/retrieve/tech/2')
data = json.load(response.get_data(as_text=True))
assert "Filtered data" in data["message"] and data["status"] == 203
Error:
TypeError: Object of type TextIOWrapper is not JSON serializable
File (posts.json):
[
{
"postid": 2,
"title": "Heading 2",
"text": "Content of post 2",
"published": "YYYY/MM/DD hh:mm:ss",
"community": "tech"
},
{
"postid": 3,
"title": "Heading 3",
"text": "Content of post 3",
"published": "YYYY/MM/DD hh:mm:ss",
"community": "tech"
},
{
"postid": 4,
"title": "Heading 4",
"text": "Content of post 4",
"published": "YYYY/MM/DD hh:mm:ss",
"community": "art"
},
{
"postid": 5,
"title": "Heading 5",
"text": "Content of post 5",
"published": "YYYY/MM/DD hh:mm:ss",
"community": "art"
},
{
"postid": 6,
"title": "Heading 6",
"text": "Content of post 6",
"published": "YYYY/MM/DD hh:mm:ss",
"community": "science"
},
{
"postid": 7,
"title": "Heading 7",
"text": "Content of post 7",
"published": "YYYY/MM/DD hh:mm:ss",
"community": "tech"
}
]
Link to files routes and tests
Upvotes: 0
Views: 867
Reputation: 341
All errors in your test are caused by wrong usage of json module methods.
Here is a modified version of your test with comments on the changes
def test_retrieve_recent_posts_existing_community(client):
with open('posts.json') as posts_data:
posts_json = json.load(posts_data) # posts data is a TextIOWrapper object. you read it using load not dumps
# posts_json is a list and should be turned into a json string using json.dumps not dump
client.post('/api/v2/post/create', data=json.dumps(posts_json), content_type='application/json')
response = client.get('/api/v2/post/retrieve/tech/2')
data = json.loads(response.get_data(as_text=True)) # use loads not load to read the json string.
assert "Filtered data" in data["message"] and data["status"] == 203
Notice that you also have a problem in the create method. It expects one object to be passed in the json body. and you're sending an array. So either change your json file to contain one object or change the create implementation to deal with an array of objects. for example change it to the following
def create():
data_list = request.get_json()
for data in data_list:
postid = data['postid']
title = data['title']
text = data['text']
published = data['published']
community = data['community']
new_post = {
'postid': postid,
'title': title,
'text': text,
'published': published,
'community': community
}
posts.append(new_post)
return {'message': "Post created successfully!", 'status': 202}
At this point the test should run, but it would result in AssertionError. That is because you have two problem in the implementation of recent_community_posts() method.
You're extracting query parameters in the first two lines and you pass the "community" and the "top" as path parameters. so if community
will always return false unless you pass it as a parameter in the url (/api/v2/post/retrieve/tech/2?community=tech&top=2) which is redundant.
You're using jsonify inside the dictionary in the return statement like this:
return {'data': jsonify(filtered_posts[:top]), 'message': "Filtered data based on community", 'status': 203}
jsonify returns a flask.wrappers.Response object which is not JSON serializable. you can replace it with the following
return jsonify({
'data': filtered_posts[:top],
'message': "Filtered data based on community",
'status': 203
})
Upvotes: 1
Reputation: 2293
In your test_retrieve_recent_posts_existing_community function, you're doing
posts_json = json.dumps(posts_data)
Now json.dumps takes a python object (dicts and lists) and turns it into a string, which is the textual representation in JSON. But that is already what you have in your file. Just do this instead:
with open('posts.json') as posts_data:
posts_json = posts_data.read()
and again, in the client.post call, just do
data=posts_json
no need for json.dump.
Upvotes: 0
Reputation: 2816
To upload the body of the request:
with open('posts.json') as posts_data:
posts_json = json.load(posts_data)
Which output should be a list:
print(type(posts_json))
list
As to post the body should by dumped:
data=json.dumps(posts_json)
Which is a string:
Out[9]: '[{"postid": 2, "title": "Heading 2", "text": "Content of post 2", "published": "YYYY/MM/DD hh:mm:ss", "community": "tech"}, {"postid": 3, "title": "Heading 3", "text": "Content of post 3", "published": "YYYY/MM/DD hh:mm:ss", "community": "tech"}, {"postid": 4, "title": "Heading 4", "text": "Content of post 4", "published": "YYYY/MM/DD hh:mm:ss", "community": "art"}, {"postid": 5, "title": "Heading 5", "text": "Content of post 5", "published": "YYYY/MM/DD hh:mm:ss", "community": "art"}, {"postid": 6, "title": "Heading 6", "text": "Content of post 6", "published": "YYYY/MM/DD hh:mm:ss", "community": "science"}, {"postid": 7, "title": "Heading 7", "text": "Content of post 7", "published": "YYYY/MM/DD hh:mm:ss", "community": "tech"}]'
I think you have posts_json dumped twice. Could you try with only once?. Please.
def test_retrieve_recent_posts_existing_community(client):
with open('posts.json') as posts_data:
posts_json = json.load(posts_data)
#SMALL CHANGE BELOW
client.post('/api/v2/post/create', data=json.dumps(posts_json), content_type='application/json')
response = client.get('/api/v2/post/retrieve/tech/2')
data = json.load(response.get_data(as_text=True))
assert "Filtered data" in data["message"] and data["status"] == 203
Upvotes: 0