librelist archives

« back to archive

How to test a webservice

How to test a webservice

From:
Pierre Aubert
Date:
2013-06-27 @ 14:58
Hello all,

i do not understand how to test the following code
here is echo.py

--------------------------------
import logging
from flask import Flask, jsonify, request
app = Flask(__name__)
app.logger.setLevel(logging.INFO)

@app.route('/', methods=['GET','POST','PUT'])
def simple():
    if request.method == 'GET':
        app.logger.info( "GET / mimetype:" + request.mimetype )
        if request.mimetype != 'application/json':
            return jsonify( {'KO': 'bad mimetype'} ), 400
        else:
            return jsonify( {'OK': '200'} )
        return jsonify( {'OK': '200'} )

    if request.method == 'POST':
        app.logger.info( "POST / mimetype:" + request.mimetype )
        if request.mimetype != 'application/json':
            return jsonify( {'KO': 'bad mimetype'} ), 400
        else:
            json = request.get_json(False,False,False)
            return jsonify( json ), 200

    if request.method == 'PUT':
        app.logger.info( "PUT / mimetype:" + request.mimetype )
        if request.mimetype != 'application/json':
            return jsonify( {'KO': 'bad mimetype'} ), 400
        else:
            json = request.get_json(False,False,False)
            return jsonify( json ), 200


if __name__ == '__main__':
    app.run(port=5000,debug=True)
--------------------------------

i try to test with

--------------------------------
import echo
import unittest

class EchoTests(unittest.TestCase):

    def setUp(self):
        self.app = echo.app.test_client()

    def tearDown(self):
        pass

    def testGet(self):
        headers = [('Content-Type', 'application/json')]
        r = self.app.get('/', headers=headers)
        assert r.status_code == 200

    def testPost(self):
        data = { 'k1': 'v1' }
        headers = [('Content-Type', 'application/json')]
        r = self.app.post('/', data=data, headers=headers)
        assert r.status_code == 200
        assert 'k1' in r.data

    def testPut(self):
        data = '{ "k1":"v1"}'
        headers = [('Content-Type', 'application/json')]
        headers.append(('Content-Length', len(data)))
        r = self.app.put('/', data=data, headers=headers)
        assert r.status_code == 200

if __name__ == '__main__':
    unittest.main()
--------------------------------

but the post and put test failed. I do not understand how to pass headers i guess.
what am'i doing wrong?

Thanks Pierre

Re: [flask] How to test a webservice

From:
Dave Shawley
Date:
2013-06-27 @ 21:46
I don't have time to verify this right now (maybe in a few hours), but I 
believe that you have to convert the data in your test to a JSON formatted
string before PUT'ing or POST'ing it.  I don't think that the test client 
will automatically jsonify the dict that you are passing in.

- dave

On Jun 27, 2013, at 10:58 AM, Pierre Aubert <pierreaubert@yahoo.fr> wrote:

> Hello all,
> 
> i do not understand how to test the following code
> here is echo.py
> 
> --------------------------------
> import logging
> from flask import Flask, jsonify, request
> app = Flask(__name__)
> app.logger.setLevel(logging.INFO)
> 
> @app.route('/', methods=['GET','POST','PUT'])
> def simple():
>    if request.method == 'GET':
>        app.logger.info( "GET / mimetype:" + request.mimetype )
>        if request.mimetype != 'application/json':
>            return jsonify( {'KO': 'bad mimetype'} ), 400
>        else:
>            return jsonify( {'OK': '200'} )
>        return jsonify( {'OK': '200'} )
> 
>    if request.method == 'POST':
>        app.logger.info( "POST / mimetype:" + request.mimetype )
>        if request.mimetype != 'application/json':
>            return jsonify( {'KO': 'bad mimetype'} ), 400
>        else:
>            json = request.get_json(False,False,False)
>            return jsonify( json ), 200
> 
>    if request.method == 'PUT':
>        app.logger.info( "PUT / mimetype:" + request.mimetype )
>        if request.mimetype != 'application/json':
>            return jsonify( {'KO': 'bad mimetype'} ), 400
>        else:
>            json = request.get_json(False,False,False)
>            return jsonify( json ), 200
> 
> 
> if __name__ == '__main__':
>    app.run(port=5000,debug=True)
> --------------------------------
> 
> i try to test with
> 
> --------------------------------
> import echo
> import unittest
> 
> class EchoTests(unittest.TestCase):
> 
>    def setUp(self):
>        self.app = echo.app.test_client()
> 
>    def tearDown(self):
>        pass
> 
>    def testGet(self):
>        headers = [('Content-Type', 'application/json')]
>        r = self.app.get('/', headers=headers)
>        assert r.status_code == 200
> 
>    def testPost(self):
>        data = { 'k1': 'v1' }
>        headers = [('Content-Type', 'application/json')]
>        r = self.app.post('/', data=data, headers=headers)
>        assert r.status_code == 200
>        assert 'k1' in r.data
> 
>    def testPut(self):
>        data = '{ "k1":"v1"}'
>        headers = [('Content-Type', 'application/json')]
>        headers.append(('Content-Length', len(data)))
>        r = self.app.put('/', data=data, headers=headers)
>        assert r.status_code == 200
> 
> if __name__ == '__main__':
>    unittest.main()
> --------------------------------
> 
> but the post and put test failed. I do not understand how to pass 
headers i guess.
> what am'i doing wrong?
> 
> Thanks Pierre
> 

--
There is a lesson here for ambitious system architects: the most dangerous
enemy of a better solution is an existing codebase that is just good 
enough. -- Eric S. Raymond.

Re: [flask] How to test a webservice

From:
Pierre Aubert
Date:
2013-06-28 @ 06:36
Hello all,

what i do not understand is:

curl work as expected:

> url -H "Content-Type: application/json" -X PUT http://127.0.0.1:5000/
> url -H "Content-Type: application/json" -X POST --data '{"k1":"v1"}' 
http://127.0.0.1:5000/
> url -H "Content-Type: application/json" -X PUT --data '{"k1":"v1"}' 
http://127.0.0.1:5000/

all return HTTP 200.

Now when i use the test client, POST and PUT tests failed. As noted by 
Dave, the post test do not use json but a dict, the put test use a json 
string.

Is it clearer?

Pierre

Le 27 juin 2013 à 23:46, Dave Shawley <daveshawley@gmail.com> a écrit :

> I don't have time to verify this right now (maybe in a few hours), but I
believe that you have to convert the data in your test to a JSON formatted
string before PUT'ing or POST'ing it.  I don't think that the test client 
will automatically jsonify the dict that you are passing in.
> 
> - dave
> 
> On Jun 27, 2013, at 10:58 AM, Pierre Aubert <pierreaubert@yahoo.fr> wrote:
> 
>> Hello all,
>> 
>> i do not understand how to test the following code
>> here is echo.py
>> 
>> --------------------------------
>> import logging
>> from flask import Flask, jsonify, request
>> app = Flask(__name__)
>> app.logger.setLevel(logging.INFO)
>> 
>> @app.route('/', meth ods=['GET','POST','PUT'])
>> def simple():
>>    if request.method == 'GET':
>>        app.logger.info( "GET / mimetype:" + request.mimetype )
>>        if request.mimetype != 'application/json':
>>            return jsonify( {'KO': 'bad mimetype'} ), 400
>>        else:
>>            return jsonify( {'OK': '200'} )
>>        return jsonify( {'OK': '200'} )
>> 
>>    if request.method == 'POST':
>>        app.logger.info( "POST / mimetype:" + request.mimetype )
>>        if request.mimetype != 'application/json':
>>            return jsonify( {'KO': 'bad mimetype'} ), 400
>>        else:
>>            json = request.get_json(False,False,False)
>>            return jsonify( json ), 200
>> 
>>    if request.method == 'PUT':
>>        app.logger.info( "PUT / mimetype:" + request.mimetype )
>>        if request.mimetype != 'application/json':
>>            return jsonify( {'KO': 'bad mimetype'} ), 400
>>        else:
>>            json = request.get_json(False,False,False)
>>            return jsonify( json ), 200
>> 
>> 
>> if __name__ == '__main__':
>>    app.run(port=5000,debug=True)
>> ------------------- -------------
>> 
>> i try to test with
>> 
>> --------------------------------
>> import echo
>> import unittest
>> 
>> class EchoTests(unittest.TestCase):
>> 
>>    def setUp(self):
>>        self.app = echo.app.test_client()
>> 
>>    def tearDown(self):
>>        pass
>> 
>>    def testGet(self):
>>        headers = [('Content-Type', 'application/json')]
>>        r = self.app.get('/', headers=headers)
>>        assert r.status_code == 200
>> 
>>    def testPost(self):
>>        data = { 'k1': 'v1' }
>>        headers = [('Content-Type', 'application/json')]
>>        r = self.app.post('/', data=data, headers=headers)
>>    ;     assert r.status_code == 200
>>        assert 'k1' in r.data
>> 
>>    def testPut(self):
>>        data = '{ "k1":"v1"}'
>>        headers = [('Content-Type', 'application/json')]
>>        headers.append(('Content-Length', len(data)))
>>        r = self.app.put('/', data=data, headers=headers)
>>        assert r.status_code == 200
>> 
>> if __name__ == '__main__':
>>    unittest.main()
>> --------------------------------
>> 
>> but the post and put test failed. I do not understand how to pass 
headers i guess.
>> what am'i doing wrong?
>> 
>> Thanks Pierre
>> 
> 
> --
> There is a lesson here for ambitious system architects: the most 
dangerous enemy of a better solution is an existing codebase that is just 
good enough. -- Eric S. Raymond.
> 

Re: [flask] How to test a webservice

From:
Dave Shawley
Date:
2013-07-01 @ 11:54
On Jun 28, 2013, at 2:36 AM, Pierre Aubert <pierreaubert@yahoo.fr> wrote:

> Now when i use the test client, POST and PUT tests failed. As noted by 
Dave, the post test do not use json but a dict, the put test use a json 
string.


I did not notice that.  The PUT test is closer to what you wanted.  In 
case you have not already figured this one out, the problem is how you 
were passing the content type to the test client.  The test client is an 
instance of werkzeug.test.Client which extends 
werkzeug.test.EnvironBuilder.  The EnvironBuilder class requires that you 
pass the content_type keyword argument if you pass a string as the data 
keyword.  Here's a working version of testPut():

    def test_that_PUT_accepts_JSON(self):
        rsp = self.app.put('/', data=json.dumps({'k1': 'v1'}),
            content_type='application/json')
        self.assertEquals(rsp.status_code, 200)

I also noticed that your GET handling is looking at 
``flask.request.mimetype``.  That isn't exactly sensical since GET cannot 
accept an entity (per RFC2616).  You might be thinking of the Accept 
header.  The best way to access this is by using 
flask.request.accept_mimetypes which is a 
werkzeug.datastructures.MIMEAccept instance.  You can check if the client 
is willing to accept JSON responses using 
``flask.request.accept_mimetypes.accept_json`` which is a ``bool``.

You probably do not want to do this.  If you can only return JSON 
responses, then return a JSON string and make sure that the Content-Type 
header is set properly (flask.jsonify will take care of this).  The client
is required to look at the Content-Type header and decide whether it can 
process the response or not.  Accept header processing is used to select 
from a set of variant representations.  You should always return a 
representation - HTTP doesn't have a response code that states that the 
server cannot generate the requested content type for this reason.

Sorry for taking so long to respond.
--
There is a lesson here for ambitious system architects: the most dangerous
enemy of a better solution is an existing codebase that is just good 
enough. -- Eric S. Raymond.

Re: [flask] How to test a webservice

From:
Pierre Aubert
Date:
2013-07-01 @ 12:07
Hello Dave,

thank you a lot. It was exactly what i needed. And for the GET part, yes i
know, it was more for understanding the behaviour. 
I had read the code from werkreug client but didn't understood what was wrong.

Pierre




________________________________
 De : Dave Shawley <daveshawley@gmail.com>
À : flask@librelist.com 
Envoyé le : Lundi 1 juillet 2013 13h54
Objet : Re: [flask] How to test a webservice
 


On Jun 28, 2013, at 2:36 AM, Pierre Aubert <pierreaubert@yahoo.fr> wrote:

Now when i use the test client, POST and PUT tests failed. As noted by 
Dave, the post test do not use json but a dict, the put test use a json 
string.
I did not notice that.  The PUT test is closer to what you wanted.  In 
case you have not already figured this one out, the problem is how you 
were passing the content type to the test client.  The test client is an 
instance of werkzeug.test.Client which extends 
werkzeug.test.EnvironBuilder.  The EnvironBuilder class requires that you 
pass the content_type keyword argument if you pass a string as the data 
keyword.  Here's a working version of testPut():

    def test_that_PUT_accepts_JSON(self):
        rsp = self.app.put('/', data=json.dumps({'k1': 'v1'}),
            content_type='application/json')
        self.assertEquals(rsp.status_code, 200)

I also noticed that your GET handling is looking at 
``flask.request.mimetype``.  That isn't exactly sensical since GET cannot 
accept an entity (per RFC2616).  You m ight be thinking of the Accept 
header.  The best way to access this is by using 
flask.request.accept_mimetypes which is a 
werkzeug.datastructures.MIMEAccept instance.  You can check if the client 
is willing to accept JSON responses using 
``flask.request.accept_mimetypes.accept_json`` which is a ``bool``.

You probably do not want to do this.  If you can only return JSON 
responses, then return a JSON string and make sure that the Content-Type 
header is set properly (flask.jsonify will take care of this).  The client
is required to look at the Content-Type header and decide whether it can 
process the response or not.  Accept header processing is used to select 
from a set of variant representations.  You should always return a 
representation - HTTP doesn't have a response code that states that the 
server cannot generate the requested content type for this reason.

Sorry for taking so long to respond.

--
There is a lesson here for ambitious system architects: the most dangerous
enemy of a better solution is an existing codebase that  is just good 
enough. -- Eric S. Raymond.

Re: [flask] How to test a webservice

From:
Lukas Baron
Date:
2013-06-27 @ 18:56
Hey Pierre,

looks like you're trying to return an non defined object "json" in the
else part of the put / post request.

Regards, Lukas

Am 27.06.2013 16:58, schrieb Pierre Aubert:
> Hello all,
> 
> i do not understand how to test the following code
> here is echo.py
> 
> --------------------------------
> import logging
> from flask import Flask, jsonify, request
> app = Flask(__name__)
> app.logger.setLevel(logging.INFO)
> 
> @app.route('/', methods=['GET','POST','PUT'])
> def simple():
>     if request.method == 'GET':
>         app.logger.info( "GET / mimetype:" + request.mimetype )
>         if request.mimetype != 'application/json':
>             return jsonify( {'KO': 'bad mimetype'} ), 400
>         else:
>             return jsonify( {'OK': '200'} )
>         return jsonify( {'OK': '200'} )
> 
>     if request.method == 'POST':
>         app.logger.info( "POST / mimetype:" + request.mimetype )
>         if request.mimetype != 'application/json':
>             return jsonify( {'KO': 'bad mimetype'} ), 400
>         else:
>             json = request.get_json(False,False,False)
>             return jsonify( json ), 200
> 
>     if request.method == 'PUT':
>         app.logger.info( "PUT / mimetype:" + request.mimetype )
>         if request.mimetype != 'application/json':
>             return jsonify( {'KO': 'bad mimetype'} ), 400
>         else:
>             json = request.get_json(False,False,False)
>             return jsonify( json ), 200
> 
> 
> if __name__ == '__main__':
>     app.run(port=5000,debug=True)
> --------------------------------
> 
> i try to test with
> 
> --------------------------------
> import echo
> import unittest
> 
> class EchoTests(unittest.TestCase):
> 
>     def setUp(self):
>         self.app = echo.app.test_client()
> 
>     def tearDown(self):
>         pass
> 
>     def testGet(self):
>         headers = [('Content-Type', 'application/json')]
>         r = self.app.get('/', headers=headers)
>         assert r.status_code == 200
> 
>     def testPost(self):
>         data = { 'k1': 'v1' }
>         headers = [('Content-Type', 'application/json')]
>         r = self.app.post('/', data=data, headers=headers)
>         assert r.status_code == 200
>         assert 'k1' in r.data
> 
>     def testPut(self):
>         data = '{ "k1":"v1"}'
>         headers = [('Content-Type', 'application/json')]
>         headers.append(('Content-Length', len(data)))
>         r = self.app.put('/', data=data, headers=headers)
>         assert r.status_code == 200
> 
> if __name__ == '__main__':
>     unittest.main()
> --------------------------------
> 
> but the post and put test failed. I do not understand how to pass 
headers i guess.
> what am'i doing wrong?
> 
> Thanks Pierre
>