Python Pyramid - 測試



編寫測試指令碼以確保程式碼正常工作被認為是一種良好的程式設計實踐。Python 生態系統有很多測試框架,包括標準庫中自帶的unittestPytest是一個流行的測試庫。它是 Pyramid 專案的首選庫。

我們將使用之前在演示PasteDeploy配置時開發的 hello 包。

首先,確保 Pyramid 環境已安裝PyTest包。

pip3 install pytest

開啟 hello 包中的setup.py檔案,並透過新增以下粗體顯示的行進行修改。

from setuptools import setup

requires = [
   'pyramid',
   'waitress',
]
dev_requires = ['pytest',]
setup(
   name='hello',
   install_requires=requires,
   extras_require={
      'dev': dev_requires,
   },
   entry_points={
      'paste.app_factory': [
         'main = hello:main'
      ],
   },
)

在這裡,每當使用以下命令安裝(或重新安裝)時,Pytest 都會作為專案依賴項新增:

pip3 install -e ".[dev]

將以下 Python 程式碼儲存為 hello 包中的 testing.py。

import unittest
from pyramid import testing
class HelloTests(unittest.TestCase):
   def test_hello_world(self):
      from . import hello_world
      request = testing.DummyRequest()
      response = hello_world(request)
      self.assertEqual(response.status_code, 200)

要執行測試,請使用以下 Pytest 命令。測試輸出如下所示:

Env\hello>pytest tests.py
========================== test session starts ==========================
platform win32 -- Python 3.10.1, pytest-7.1.2, pluggy-1.0.0
rootdir: E:\tp-pyramid\hello
collected 1 item

tests.py.
   [100%]
 
=========================== 1 passed in 1.12s ===========================

要檢查測試是否失敗,請在測試函式中引入錯誤並再次執行。

(tp-pyramid) E:\tp-pyramid\hello>pytest tests.py
========================== test session starts ==========================
collected 1 item

tests.py F 
[100%]
=============================== FAILURES ================================
______________________ HelloTests.test_hello_world ______________________
self = <hello.tests.HelloTests testMethod=test_hello_world>
   def test_hello_world(self):
      from . import hello_world
      request = testing.DummyRequest()
      response = hello_world(request)
>     self.assertEqual(response.status_code, 404)
E     AssertionError: 200 != 404

tests.py:13: AssertionError
======================== short test summary info ========================
FAILED tests.py::HelloTests::test_hello_world - AssertionError: 200 != 404
=========================== 1 failed in 1.53s ===========================

功能測試

雖然單元測試在測試驅動開發 (TDD) 方法中得到了廣泛使用,但對於 Web 應用程式,WebTest是一個執行功能測試的 Python 包。我們可以模擬針對 WSGI 應用程式的完整 HTTP 請求,然後測試響應中的資訊。

示例

讓我們使用之前示例中使用的 hello 專案。開啟 setup.py 並將 WebTest 新增為專案依賴項。

from setuptools import setup

requires = [
   'pyramid',
   'waitress',
]
dev_requires = ['pytest','webtest',]
setup(
   name='hello',
   install_requires=requires,
   extras_require={
      'dev': dev_requires,
   },
   entry_points={
      'paste.app_factory': [
         'main = hello:main'
      ],
   },
)

重新安裝 hello 包及其新的開發模式依賴項。

Env\hello>..\scripts\pip3 install -e ".[dev]"

tests.py檔案中包含一個功能測試

import unittest
from pyramid import testing

class HelloTests(unittest.TestCase):

   def test_hello_world(self):
      from . import hello_world
      request = testing.DummyRequest()
      response = hello_world(request)
      self.assertEqual(response.status_code, 200)
class HelloFunctionalTests(unittest.TestCase):
   def setUp(self):
      from . import main
      app = main({})
      from webtest import TestApp
      self.testapp = TestApp(app)
   def test_hello_world(self):
      res = self.testapp.get('/', status=200)
      self.assertIn(b'<h1>Hello World!</h1>', res.body)

輸出

最後,根據以下命令執行 Pytest:

Env\hello>pytest tests.py
========================== test session starts ==========================
platform win32 -- Python 3.10.1, pytest-7.1.2, pluggy-1.0.0
rootdir: E:\tp-pyramid\hello
collected 2 items
tests.py .. [100%]

=========================== 2 passed in 2.37s ===========================

Cookiecutter 專案中的測試

CookieCutter 實用程式自動生成包含功能測試和單元測試的 tests 包。我們之前曾使用 Cookiecutter 構建了一個名為 testproj 的 Pyramid 專案。在這個專案中,我們找到了 tests 資料夾。

示例

test_functional.py 包含以下測試函式:

from testproj import models

def test_my_view_success(testapp, dbsession):
   model = models.MyModel(name='one', value=55)
   dbsession.add(model)
   dbsession.flush()
   res = testapp.get('/', status=200)
   assert res.body
   
def test_notfound(testapp):
   res = testapp.get('/badurl', status=404)
   assert res.status_code == 404

test_views.py 定義了以下測試函式來測試檢視:

from testproj import models
from testproj.views.default import my_view
from testproj.views.notfound import notfound_view

def test_my_view_failure(app_request):
info = my_view(app_request)
assert info.status_int == 500

def test_my_view_success(app_request, dbsession):
   model = models.MyModel(name='one', value=55)
   dbsession.add(model)
   dbsession.flush()
   info = my_view(app_request)
   assert app_request.response.status_int == 200
   assert info['one'].name == 'one'
   assert info['project'] == 'testproj'
def test_notfound_view(app_request):
   info = notfound_view(app_request)
   assert app_request.response.status_int == 404
   assert info == {}

輸出

這些測試由以下命令執行:

Env\testproj>Pytest
========================== test session starts ==========================
platform win32 -- Python 3.10.1, pytest-7.1.2, pluggy-1.0.0
rootdir: Env\testproj, configfile: pytest.ini, testpaths: testproj, tests
plugins: cov-3.0.0
collected 5 items

tests\test_functional.py .. [ 40%]
tests\test_views.py ... [100%]
=============== 5 passed, 20 warnings in 6.66s ===============
廣告