上一篇介紹了 Pyramid 開發 API 並使用 Postman 來測試功能是否正常,接下來會寫 unitest、function test,後面會導入自動化測試,測試自動化也是 DevOps 很重要的一環,以下是我們碰到導入測試程式的困難點,提出來讓大家一起思考.
test_initdb.py : 測試初始化 DB script
import os
import unittest
from ithome_pellok_2018.scripts.initializedb import main
class TestInitializeDB(unittest.TestCase):
def test_usage(self):
with self.assertRaises(SystemExit):
main(argv=['ithome_pellok_2018'])
def test_run(self):
path = os.path.abspath(os.path.join(os.path.dirname("__file__")))
main(argv=['ithome_pellok_2018',
'{}/development.ini'.format(path)])
self.assertTrue(os.path.exists('{}/ithome_pellok_2018.sqlite'.format(path)))
os.remove('{}/ithome_pellok_2018.sqlite'.format(path))
test_mymodel_model.py : 測試對應資料表
import unittest
import transaction
from pyramid import testing
from ithome_pellok_2018.models import (
get_tm_session,
)
from ithome_pellok_2018.models.meta import Base
from ithome_pellok_2018.models import MyModel
class BaseTest(unittest.TestCase):
def setUp(self):
self.config = testing.setUp(settings={
'sqlalchemy.url': 'sqlite:///:memory:'
})
self.config.include('ithome_pellok_2018.models')
session_factory = self.config.registry['dbsession_factory']
self.session = get_tm_session(session_factory, transaction.manager)
self.init_database()
def init_database(self):
session_factory = self.config.registry['dbsession_factory']
engine = session_factory.kw['bind']
Base.metadata.create_all(engine)
def tearDown(self):
testing.tearDown()
transaction.abort()
def create_mymodel(self, name, value):
return MyModel(name=name, value=value)
class TestMymodel(BaseTest):
def test__saved(self):
name = 'foo'
value = 'bar'
mymodel = self.create_mymodel(name=name, value=value)
self.assertEqual(mymodel.name, name)
self.assertEqual(mymodel.value, value)
test_api_unitest.py : 測試 API 輸入輸出格式功能是否正常
import unittest
import transaction
from pyramid import testing
from ithome_pellok_2018.models import (
get_engine,
get_session_factory,
get_tm_session,
)
from ithome_pellok_2018.models.meta import Base
from ithome_pellok_2018.models import MyModel
from ithome_pellok_2018.views.api import ApiView
def dummy_request(dbsession):
return testing.DummyRequest(dbsession=dbsession)
class BaseTest(unittest.TestCase):
def setUp(self):
self.config = testing.setUp(settings={
'sqlalchemy.url': 'sqlite:///:memory:'
})
self.config.include('ithome_pellok_2018.models')
settings = self.config.get_settings()
self.engine = get_engine(settings)
session_factory = get_session_factory(self.engine)
self.session = get_tm_session(session_factory, transaction.manager)
def init_database(self):
Base.metadata.create_all(self.engine)
def tearDown(self):
testing.tearDown()
transaction.abort()
Base.metadata.drop_all(self.engine)
class TestApiView(BaseTest):
def setUp(self):
super(TestApiView, self).setUp()
self.init_database()
def create_mymodel(self, name='one', value='123'):
"""
創建 Table 資料
"""
mymodel = MyModel(name=name, value=value)
self.session.add(mymodel)
mymodel = self.session.query(MyModel)\
.filter(MyModel.name == name).first()
return mymodel
def test_create(self):
"""
測試 創建 API 資料
"""
request = dummy_request(self.session)
name = 'one'
value = 'test'
request.params = {'name': name, 'value': value}
api_view = ApiView(request)
info = api_view.create()
self.assertEqual(info.get('code', 500), 200)
self.assertEqual(info.get('status', False), True)
self.assertEqual(info.get('response', {}).get('name'), name)
self.assertEqual(info.get('response', {}).get('value'), value)
return info.get('response', {})
def test_search(self):
"""
測試 搜尋 API 資料
"""
request = dummy_request(self.session)
api_view = ApiView(request)
info = api_view.search()
self.assertEqual(info.get('code', 500), 200)
self.assertEqual(info.get('status', False), True)
self.assertEqual(len(info.get('response')), 0)
def test_get(self):
"""
測試 讀取 API 資料
"""
mymodel = self.create_mymodel()
request = dummy_request(self.session)
request.matchdict['id'] = mymodel.id
api_view = ApiView(request)
info = api_view.get()
self.assertEqual(info.get('code', 500), 200)
self.assertEqual(info.get('status', False), True)
self.assertEqual(info.get('response', {}).get('name'), mymodel.name)
self.assertEqual(info.get('response', {}).get('value'), mymodel.value)
def test_update(self):
"""
測試 更新 API 資料
"""
mymodel = self.create_mymodel()
request = dummy_request(self.session)
request.matchdict['id'] = mymodel.id
name = 'one'
value = 'test'
request.params = {'name': name, 'value': value}
api_view = ApiView(request)
info = api_view.edit()
self.assertEqual(info.get('code', 500), 200)
self.assertEqual(info.get('status', False), True)
self.assertEqual(info.get('response', {}).get('name'), name)
self.assertEqual(info.get('response', {}).get('value'), value)
def test_delete(self):
"""
測試 刪除 API 資料
"""
mymodel = self.create_mymodel()
request = dummy_request(self.session)
request.matchdict['id'] = mymodel.id
api_view = ApiView(request)
info = api_view.delete()
self.assertEqual(info.get('code', 500), 200)
self.assertEqual(info.get('status', False), True)
self.assertEqual(info.get('response'), 'OK')
會安裝 setup.py 的 test_require
tests_require = [
'WebTest >= 1.3.1', # py3 compat
'pytest', # includes virtualenv
'pytest-cov',
]
安裝指令
cd ithome_pellok_2018
env/bin/pip install -e .[testing]
指令執行
source env/bin/activate
py.test
或
env/bin/py.test
或
source env/bin/activate
python setup.py test
以上是透過 py.test 來實作測試程式
bitbucket Repostory
pyramid tests