【问题标题】:How to get an actual Pyramid request when unit testing单元测试时如何获取实际的 Pyramid 请求
【发布时间】:2012-11-20 23:36:35
【问题描述】:

我有一个 Pyramid 应用程序,我仍在努力学习。我应该为它编写单元测试,但我不知道如何构建请求。

我看到 Pyramid 有一个带有 DummyRequest 的测试模块,但这是空白的,显然如果我将它传递到视图中,它将失败,因为它没有填充请求在运行时将具有的属性。

所以问题是,如何在测试时传递看起来像运行时请求的请求?

【问题讨论】:

    标签: python unit-testing pyramid


    【解决方案1】:

    每当您进行单元测试(与功能测试不同)时,要意识到您正在测试一个小“单元”。该单元(在这种情况下是您的视图)不需要“真正的”请求,也不需要完整的工作系统。该视图对自称为“请求”的对象可能具有的某些期望,但仅此而已,并且它当然不需要真实请求中可用的所有内容。这就是模拟或虚拟对象发挥作用的地方。你想测试你的视图,所以你可以将一些东西传递到你的视图中,它需要检查它是否在做这项工作。假设您有以下配置:

    def main():
        config = Configurator()
        config.add_route('user', '/users/{uid}')
        return config.make_wsgi_app()
    
    @view_config(route_name='user', renderer='user_template.mako')
    def user_view(request):
        uid = request.matchdict['uid']
        user = find_user(request, uid)
        if user is None:
            raise HTTPNotFound
        return {'user': user}
    
    def find_user(request, uid):
        return request.db.query(User).filter_by(id=uid).first()
    

    太好了,这是一个真实的视图,您会注意到它只要求请求具有 2 个属性,matchdictdb。好吧,我们可以这样做:

    class Test_user_view(unittest.TestCase):
        def test_it(self):
            req = DummyRequest()
            req.db = DummyDB()
            req.matchdict = {'uid': '3'}
            result = user_view(req)
            self.assertEqual(result['user'].id, 3)
    

    现在我们在这里没有解决的一件事是DummyDB 的实现,但更好的方法可能是模拟出find_user 以返回一个虚拟值。这使测试保持简单并专注于视图本身,而不会陷入与数据库的对话。那是一个单独的测试。

    这里的其他答案更彻底地涵盖了功能测试,您应该一定要考虑使用 WebTest 来帮助确保您的整个应用程序按预期工作,但这不是单元测试的领域。

    【讨论】:

    • 实现request.db.query 方法的最佳实践是什么? MagicMock()?回想起来,SQLAlchemy 中的查询实际上会返回User 的一个实例,因此可以模拟让DummyDB().query() 方法返回预期的用户编号?
    【解决方案2】:

    如果您还没有这样做,请查看 Pyramid unit vs integration vs functional testingPyramid testing guidelines。恕我直言,从功能测试开始,而不是使用 DummyRequest 进行单元测试,在许多情况下往往会给出更好的结果(即更容易实现和维护)。我建议使用Webtest (examples in pyramid docs)Selenium 库(或两者的组合)。使用 webtest 将允许您测试基本功能,并且测试通常会比 Selenium 运行得更快。 Selenium 实际上可以启动浏览器并允许更精细的控制。因为它会启动浏览器,所以 selenium 测试往往需要更长的时间才能运行。我认为一个好的经验法则是,如果您只需要基本测试(例如,查看特定页面是否加载),那么坚持使用 Webtest。如果您的测试需要对浏览器进行更多控制(例如调试 javascript),请尝试 Selenium。查看上面链接的文档,了解如何使用这些库进行测试的示例。

    【讨论】:

      【解决方案3】:

      您可以在 setUp 函数中构建这样的“假”请求:

      request = testing.DummyRequest()
      request.errors = errors.Errors([])
      request.validated = {}
      

      然后在您的一个测试中设置您想要测试的参数。像这样:

      request.GET['app_id'] = 'xxxxxxxxx'
      valid_register(request)
      self.assertTrue('app_id' in request.validated)
      

      希望对你有帮助

      【讨论】:

        【解决方案4】:

        我认为 Brian 的回答很好,但会补充说“尽可能多地编写易于测试的代码”是一个有用的口头禅。如果您可以将功能模块化并编写易于使用您熟悉的非请求依赖方式进行单元测试的可移植库,您会很高兴。

        功能测试比单元测试更难、更慢、更差一个数量级;正如布赖恩所提到的,Webtest 是 Pyramid 的所在。硒是另一个数量级的更难、更混乱、更慢。当心;如果您的测试依赖于实际数据,那么随着数据的变化,它们会随着时间的推移而中断。模拟和良好的虚拟数据可以帮助解决这个问题。在必要时使用更高级别、更困难的测试形式,但不仅仅是为了好玩——您可以在某种程度上使用您的架构来减少对它的需求。

        要回答实际的“你如何”问题:如果你有类似 Webtest 的东西,你只需做一些设置,然后做类似的事情

        response = app.get('/form.html')
        

        然后你有一个方便的响应对象,其中包含你想要的所有信息,然后你写你的断言。 tutorial in the docs 会比我解释得更好。

        【讨论】:

          猜你喜欢
          • 2014-07-04
          • 2016-03-08
          • 2018-06-19
          • 1970-01-01
          • 2021-10-03
          • 1970-01-01
          • 2012-05-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多