0

我正在尝试在 Flask-Restplus 站点中测试 ToDo 的示例,但它一直让我 404 ......

基本上我有3个文件:

应用程序.py

import sys
import os
import platform
import datetime
import logging    
from logging import Formatter
from logging.handlers import RotatingFileHandler

from jinja2 import Environment, PackageLoader

from flask import Flask, url_for, render_template, abort, request, Blueprint
from flask.ext.restplus import Api, Resource, fields
from werkzeug.contrib.fixers import ProxyFix


api_v1 = Blueprint('api', __name__, url_prefix='/api/1')


ns = api.namespace('todos', description='TODO operations')

TODOS = {
    'todo1': {'task': 'build an API'},
    'todo2': {'task': '?????'},
    'todo3': {'task': 'profit!'},
}


todo = api.model('Todo', {
    'task': fields.String(required=True, description='The task details')
})

listed_todo = api.model('ListedTodo', {
    'id': fields.String(required=True, description='The todo ID'),
    'todo': fields.Nested(todo, description='The Todo')
})


def abort_if_todo_doesnt_exist(todo_id):
    if todo_id not in TODOS:
        api.abort(404, "Todo {} doesn't exist".format(todo_id))

parser = api.parser()
parser.add_argument('task', type=str, required=True, help='The task details', location='form')

@ns.route('/<string:todo_id>')
@api.doc(responses={404: 'Todo not found'}, params={'todo_id': 'The Todo ID'})
class Todo(Resource):
    '''Show a single todo item and lets you delete them'''
    @api.doc(description='todo_id should be in {0}'.format(', '.join(TODOS.keys())))
    @api.marshal_with(todo)
    def get(self, todo_id):
        '''Fetch a given resource'''
        abort_if_todo_doesnt_exist(todo_id)
        return TODOS[todo_id]

    @api.doc(responses={204: 'Todo deleted'})
    def delete(self, todo_id):
        '''Delete a given resource'''
        abort_if_todo_doesnt_exist(todo_id)
        del TODOS[todo_id]
        return '', 204

    @api.doc(parser=parser)
    @api.marshal_with(todo)
    def put(self, todo_id):
        '''Update a given resource'''
        args = parser.parse_args()
        task = {'task': args['task']}
        TODOS[todo_id] = task
        return task


@ns.route('/')
class TodoList(Resource):
    '''Shows a list of all todos, and lets you POST to add new tasks'''
    @api.marshal_list_with(listed_todo)
    def get(self):
        '''List all todos'''
        return [{'id': id, 'todo': todo} for id, todo in TODOS.items()]

    @api.doc(parser=parser)
    @api.marshal_with(todo, code=201)
    def post(self):
        '''Create a todo'''
        args = parser.parse_args()
        todo_id = 'todo%d' % (len(TODOS) + 1)
        TODOS[todo_id] = {'task': args['task']}
        return TODOS[todo_id], 201


app = Flask(__name__)

app.secret_key = "secretkey"
app.config.from_pyfile('settings.py')

if os.path.exists(os.path.join(app.root_path, 'local_settings.py')):
    app.config.from_pyfile('local_settings.py')


app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://%s@%s/%s' % (
    app.config['DB_USER'], app.config['DB_HOST'], app.config['DB_NAME'])

主文件

import sys

from flask import Blueprint

from portal.app import app
from portal import libs

if __name__ == '__main__':
    if len(sys.argv) == 2:
        port = int(sys.argv[1])
    else:
        port = 5000

    host = app.config.get('HOST', '127.0.0.1')

    from portal.app import api_v1
    app.register_blueprint(api_v1)

    import os
    app.root_path = os.getcwd()
    print "Running in", app.root_path, " with DEBUG=", app.config.get('DEBUG', False)
    app.run(host,
            port,
            app.config.get('DEBUG', False),
            use_reloader=True
    )

测试.py

class ApiTests(helpers.ViewBase):

    ############################
    #### setup and teardown ####
    ############################

    def setUp(self):
        super(ApiTests, self).setUp()
        app.config['TESTING'] = True
        app.config['WTF_CSRF_ENABLED'] = False
        app.config['DEBUG'] = False
        self.assertEquals(app.debug, False)

    # executed after to each test
    def tearDown(self):
        pass

    ###############
    #### tests ####
    ###############
    def test_can_obtain_todos(self):
        response = self.client.get('/api/1/todos')
        self.assertEqual(response.status_code, 200)

如果我运行该应用程序,我可以毫无问题地访问http://localhost:5000/api/1/todos ,但如果我运行测试,我会不断收到 404 路由异常

Traceback (most recent call last):
File "/home/internetmosquito/python_envs/portal/local/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/home/internetmosquito/python_envs/portal/local/lib/python2.7/site-packages/flask/app.py", line 1617, in dispatch_request
self.raise_routing_exception(req)
File "/home/internetmosquito/python_envs/portal/local/lib/python2.7/site-packages/flask/app.py", line 1600, in raise_routing_exception
raise request.routing_exception
NotFound: 404: Not Found
> /home/internetmosquito/git/wizbots/portal/src/portal/test/test_api.py(47)test_can_obtain_todos()

知道我在这里缺少什么吗?谢谢!

4

1 回答 1

1

仅作记录,测试失败是因为我没有在测试文件中再次正确初始化蓝图……这是在 main.py 中完成的,以避免我遇到的循环依赖问题。

因此,只需重新创建蓝图并将其分配给测试文件中的 setUp 中的应用程序就可以了,但这效率不高,应该避免,猜想我应该检查为什么会发生循环依赖并在 app.py 中执行所有操作而是文件...

于 2016-11-20T22:29:36.340 回答