Неверный запрос при публикации JSON на конечную точку Flask в модульном тесте

Я нашел множество вопросов о людях, пытающихся опубликовать JSON в приложении Flask, но ни одна из них не является проблемой, с которой я столкнулся здесь.

У меня есть простой REST API, построенный с использованием Flask и Flask-JWT, который отлично работает через браузер, но я выполнил блок с моими модульными тестами. Приложение представляет собой приложение App Engine и отлично работает на локальном сервере разработчиков и на App Engine. Я провожу свои юнит-тесты с python -m unittest <module>,

У меня есть базовое приложение Flask, созданное с использованием простой фабрики:

def create_app(name=__name__, cfg):
    app = Flask(name)
    app.config.update(cfg)

    CORS(app)
    JWT(app, auth_handler, identity_handler)

    @app.route('/api/v1/ping', methods=['GET'])
    def handle_ping():
        return jsonify({'message': 'pong'})

    # other routes ...

В приведенном выше JWT ожидает authentication_handler, который я реализовал:

def auth_handler(identity, secret):
    # validate identity and secret
    return User(...)

Мой клиент - Angular.js, поэтому я отправляю JSON на эту конечную точку. Это все нормально работает в браузере или с curl:

$ curl -H "content-type:application/json" -d '{"username":"jackripper@example.com","password":"crm114"}'   http://localhost:8080/api/v1/auth

давая мне 200 OK и токен доступа в ответе.

Мои простые тестовые примеры идут примерно так:

conf = {
     'DEBUG': False,
    'TESTING': True,
    'SECRET_KEY': 'MoveAlongTheresNothingToSeeHere',
    'JWT_AUTH_URL_RULE': '/api/v1/auth'
}

class FlaskRouteTests(unittest.TestCase):
    def setUp(self):
        api = factory.create_app(__name__, conf)
        self.app = api.test_client()

    def tearDown(self):
        pass

    def testRoute(self):
        # This test works just fine
        resp = self.app.get('/api/v1/ping')
        self.assertEqual(resp.status, "200 OK", "Status should be 200, was %s" % resp.status)

    def testAuth(self):
        # This test does not work
        resp = self.app.post('http://localhost:8080/api/v1/auth',
                         data="{'username': 'jackripper@example.com', 'password': 'crm114'}",
                         content_type='application/json', charset='UTF-8')
        self.assertEqual(resp.status, "200 OK", "Status should be 200, was %s" % resp.status)

Старая добрая GET тестовое задание (testRoute()) работает просто отлично но testAuth() дает мне 400 Bad Request и я не могу понять, почему.

Если я посмотрю на werkzeug environ непосредственно перед отправкой запроса в мое приложение Flask, я вижу это:

{
 'SERVER_PORT': '8080',
 'SERVER_PROTOCOL': 'HTTP/1.1',
 'SCRIPT_NAME': '',
 'wsgi.input': <_io.BytesIO object at 0x111fa8230>,
 'REQUEST_METHOD': 'POST',
 'HTTP_HOST': 'localhost:8080',
 'PATH_INFO': '/api/v1/auth',
 'wsgi.multithread': False,
 'QUERY_STRING': '',
 'HTTP_CONTENT_TYPE': 'application/json',
 'HTTP_CONTENT_LENGTH': '53',
 'CONTENT_LENGTH': '53',
 'wsgi.version': (1, 0),
 'SERVER_NAME': 'localhost',
 'wsgi.run_once': False,
 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x10fd2d1e0>,
 'wsgi.multiprocess': False,
 'flask._preserve_context': False,
 'wsgi.url_scheme': 'http',
 'CONTENT_TYPE': u'application/json'
}

Таким образом, тип содержимого установлен правильно, и если я прочитал содержимое wsgi.input (BytesIO.getvalue()) Я вижу {'username': 'jackripper@example.com', 'password': 'crm114'}

Кажется, запрос где-то терпит неудачу, прежде чем он даже ударил auth_handler Так что где-то в werkzeug или Flask.

  • Werkzeug EnvironBuilder интерпретирует данные как str и преобразует его в BytesIO поток - я не знаю, ожидается ли это.
  • Я пытался разместить данные как в виде строки: data="{'username': 'jackripper@example.com', 'password': 'password'}" и как диктат: data={'username': 'jackripper@example.com', 'password': 'password'}, но, похоже, не имеет значения.

Итак, мой вопрос: как мне разместить JSON на конечной точке в модульном тесте с Flask.test_client()? Я что-то упускаю из виду?

1 ответ

Решение

Вы не публикуете действительный JSON:

data="{'username': 'jackripper@example.com', 'password': 'crm114'}",

Обратите внимание на одинарные кавычки. JSON использует двойные кавычки; следующее будет действительным JSON:

data='{"username": "jackripper@example.com", "password": "crm114"}',
Другие вопросы по тегам