【问题标题】:Test Redirection In Flask with Python Unittest使用 Python Unittest 在 Flask 中测试重定向
【发布时间】:2014-06-02 11:58:18
【问题描述】:

我目前正在尝试为我的 Flask 应用程序编写一些单元测试。在我的许多视图功能(例如我的登录)中,我重定向到一个新页面。比如:

@user.route('/login', methods=['GET', 'POST'])
def login():
    ....
    return redirect(url_for('splash.dashboard'))

我正在尝试验证此重定向是否发生在我的单元测试中。现在,我有:

def test_register(self):
    rv = self.create_user('John','Smith','John.Smith@myschool.edu', 'helloworld')
    self.assertEquals(rv.status, "200 OK")
    # self.assert_redirects(rv, url_for('splash.dashboard'))

这个函数确实确保返回的响应是 200,但最后一行显然是无效的语法。我怎么能断言呢?我的create_user 函数很简单:

def create_user(self, firstname, lastname, email, password):
        return self.app.post('/user/register', data=dict(
            firstname=firstname,
            lastname=lastname,
            email=email,
            password=password
        ), follow_redirects=True)

【问题讨论】:

    标签: python unit-testing flask python-unittest


    【解决方案1】:

    Flask 有 built-in testing hooks 和一个测试客户端,非常适合这类功能性的东西。

    from flask import url_for, request
    import yourapp
    
    test_client = yourapp.app.test_client()
    with test_client:
        response = test_client.get(url_for('whatever.url'), follow_redirects=True)
        # check that the path changed
        assert request.path == url_for('redirected.url')
    

    对于旧版本的 Flask/Werkzeug,请求可能在响应中可用:

    from flask import url_for
    import yourapp
    
    test_client = yourapp.app.test_client()
    response = test_client.get(url_for('whatever.url'), follow_redirects=True)
    
    # check that the path changed
    assert response.request.path == url_for('redirected.url')
    

    文档提供了有关如何执行此操作的更多信息,但仅供参考,如果您看到“flaskr”,那是测试类的名称,而不是 Flask 中的任何内容,这让我第一次看到它时感到困惑。

    【讨论】:

    • 我强烈鼓励人们使用这个解决方案,它消除了对 Flask-Testing 的依赖(总的来说,我认为使用尽可能少的扩展是一件好事,或者只有“稳定”和“大”诸如 Flask-Principal、Flask-Security 等)。但是,此解决方案引发了RuntimeError: Attempted to generate a URL without the application context being pushed. This has to be executed when application context is available,因为url_for 需要应用程序上下文。你所要做的就是把它放在with app.app_context():
    • "response.request" --> AttributeError: 'Response' object has no attribute 'request'
    • 不确定response.request 是什么,但如果您使用with app.test_client() as c: 保留请求上下文,那么您只需导入request 和url_for 并执行request.path == url_for(...
    • 根据我的测试,我认为使用 request.path 不会起作用,因为路径设置为初始 URL,而不是重定向后的 URL。 @DyRuss
    • 从我的测试中,我可以确认使用客户端作为上下文 (with client) 确实会在调用 client.get 时更改 request 上下文(并且 follow_redirects=True)。谢谢@DyRuss
    【解决方案2】:

    您可以使用 Flask test client 作为 context manager(使用 with 关键字)来验证重定向后的最终路径。它允许保留最终请求上下文,以便导入包含请求路径的request object

    from flask import request, url_for
    
    def test_register(self):
        with self.app.test_client() as client:
            user_data = dict(
                firstname='John',
                lastname='Smith',
                email='John.Smith@myschool.edu',
                password='helloworld'
            )
            res = client.post('/user/register', data=user_data, follow_redirects=True)
            assert res.status == '200 OK'
            assert request.path == url_for('splash.dashboard')
    

    【讨论】:

      【解决方案3】:

      一种方法是不遵循重定向(从您的请求中删除 follow_redirects,或将其明确设置为 False)。

      然后,您可以简单地将self.assertEquals(rv.status, "200 OK") 替换为:

      self.assertEqual(rv.status_code, 302)
      self.assertEqual(rv.location, url_for('splash.dashboard', _external=True))
      

      如果您出于某种原因想继续使用follow_redirects,另一种(稍微脆弱的)方法是检查一些预期的仪表板字符串,例如rv.data 的响应中的HTML 元素ID。例如self.assertIn('dashboard-id', rv.data)

      【讨论】:

        【解决方案4】:

        试试Flask-Testing

        assertRedirects的api你可以用这个

        assertRedirects(response, location)
        
        Checks if response is an HTTP redirect to the given location.
        Parameters: 
        
            response – Flask response
            location – relative URL (i.e. without http://localhost)
        

        测试脚本:

        def test_register(self):
            rv = self.create_user('John','Smith','John.Smith@myschool.edu', 'helloworld')
            assertRedirects(rv, url of splash.dashboard)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-24
          • 1970-01-01
          相关资源
          最近更新 更多