Jak wysyłać żądania z kodami JSON w testach jednostkowych

99

Mam kod w aplikacji Flask, która używa JSON w żądaniu i mogę pobrać obiekt JSON w następujący sposób:

Request = request.get_json()

To działa dobrze, jednak próbuję tworzyć testy jednostkowe za pomocą modułu unittest Pythona i mam trudności ze znalezieniem sposobu na wysłanie JSON z żądaniem.

response=self.app.post('/test_function', 
                       data=json.dumps(dict(foo = 'bar')))

To daje mi:

>>> request.get_data()
'{"foo": "bar"}'
>>> request.get_json()
None

Wydaje się, że Flask ma argument JSON, w którym można ustawić json = dict (foo = 'bar') w żądaniu postu, ale nie wiem, jak to zrobić z modułem unittest.

Sepehr Nazari
źródło
Co request.datazawiera? Często, gdy parsowanie json kończy się niepowodzeniem z powodu nieprawidłowych danych wejściowych, kończy się niepowodzeniem i zwraca, Nonewięc nieprzetworzone dane wejściowe mogą nie być json.
Benoît Latinier
>>> request.get_data () '{"foo": "bar"}' >>> request.get_json () Brak Nie jestem do końca pewien, jak działa żądanie flask, ale wydaje się, że oddziela dane od json, a ja nie mogę dowiedzieć się, jak wysłać informacje do json, a nie dane, jeśli ma to jakiś sens.
Sepehr Nazari
9
Myślę, że to nagłówki typu zawartości, spróbuj ustawić je na appliacation / json. również parametr force jest pomocny, ale prawdopodobnie nie chcesz tam iść tylko po to, aby przejść unittests, lepiej zmienić mime
user3012759

Odpowiedzi:

198

Zmiana posta na

response=self.app.post('/test_function', 
                       data=json.dumps(dict(foo='bar')),
                       content_type='application/json')

naprawione.

Dzięki user3012759.

Sepehr Nazari
źródło
niszczył mi tym głowę. Nie rozumiem, dlaczego musisz zrzucić dane, skoro już określasz application/jsontyp zawartości.
dimmg
Wydaje mi się, że dzieje się tak, ponieważ wszystko, co wysyłasz w poście, musi być ciągiem.
Sepehr Nazari
17
Niesamowite, że nie ma tego w dokumentacji, ponieważ test_client flask nie ma dokumentacji API!
rjurney
Jak uzyskać dane z odpowiedzi?
zmienna
@variable, z odpowiedzią z post żądania, taką jak resp = client.post('/my/endpoint/',json=my_json_data)dostęp do danych w bajtach z resp.data.
amiabl
44

AKTUALIZACJA: Ponieważ flask.testing.FlaskClientmetody wydane w Flask 1.0 akceptują jsonargument i Response.get_jsondodaną metodę, zobacz przykład .

dla Flask 0.x możesz skorzystać z poniższego paragonu:

from flask import Flask, Response as BaseResponse, json
from flask.testing import FlaskClient
from werkzeug.utils import cached_property


class Response(BaseResponse):
    @cached_property
    def json(self):
        return json.loads(self.data)


class TestClient(FlaskClient):
    def open(self, *args, **kwargs):
        if 'json' in kwargs:
            kwargs['data'] = json.dumps(kwargs.pop('json'))
            kwargs['content_type'] = 'application/json'
        return super(TestClient, self).open(*args, **kwargs)


app = Flask(__name__)
app.response_class = Response
app.test_client_class = TestClient
app.testing = True
Victor Gavro
źródło
1
I nie zapominaj, że argument json nie może być dictłańcuchem JSON!
LaundroMat