だから、 を考えてください。単体テストの作成を試みている単純なライブラリがあります。このライブラリはデータベースと通信し、そのデータを使用してSOAP APIを呼び出します。私は3つのモジュールと各モジュールのテストファイルを持っています。サブモジュール内の関数をテストするためのPythonモックを使用したベストプラクティス
ディレクトリ構造:
./mypkg
../__init__.py
../main.py
../db.py
../api.py
./tests
../test_main
../test_db
../test_api
コード:
#db.py
import mysqlclient
class Db(object):
def __init__(self):
self._client = mysqlclient.Client()
@property
def data(self):
return self._client.some_query()
#api.py
import soapclient
class Api(object):
def __init__(self):
self._client = soapclient.Client()
@property
def call(self):
return self._client.some_external_call()
#main.py
from db import Db
from api import Api
class MyLib(object):
def __init__(self):
self.db = Db()
self.api = Api()
def caller(self):
return self.api.call(self.db.data)
ユニット-実験:
#test_db.py
import mock
from mypkg.db import Db
@mock.patch('mypkg.db.mysqlclient')
def test_db(mysqlclient_mock):
mysqlclient_mock.Client.return_value.some_query = {'data':'data'}
db = Db()
assert db.data == {'data':'data'}
#test_api.py
import mock
from mypkg.api import Api
@mock.patch('mypkg.db.soapclient')
def test_db(soap_mock):
soap_mock.Client.return_value.some_external_call = 'foo'
api = Api()
assert api.call == 'foo'
上記の例では、mypkg.main.MyLib
は(サードパーティmysqlclient
を使用)mypkg.db.Db()
を呼び出しmypkg.api.Api()
(サードパーティのを使用))
私は別にtest_db
とtest_api
に私のDBとのAPI呼び出しを模擬するために、サードパーティのライブラリにパッチを適用するmock.patch
を使用しています。
私の質問はtest_main
にこれらの外部呼び出しを再度パッチするか、単にdb.Db
とapi.Api
というパッチを貼っておくことをお勧めしますか? (この例は非常に単純ですが、大規模なライブラリでは、外部呼び出しを再度パッチするときや、内部ライブラリにパッチを当てるテストヘルパ関数を使用しているときでも、コードが煩雑になります)。
オプション1:再びmain
でパッチ外部のライブラリ
#test_main.py
import mock
from mypkg.main import MyLib
@mock.patch('mypkg.db.mysqlclient')
@mock.patch('mypkg.api.soapclient')
def test_main(soap_mock, mysqlcient_mock):
ml = MyLib()
soap_mock.Client.return_value.some_external_call = 'foo'
assert ml.caller() == 'foo'
オプション2:パッチ内部ライブラリ
#test_main.py
import mock
from mypkg.main import MyLib
@mock.patch('mypkg.db.Db')
@mock.patch('mypkg.api.Api')
def test_main(api_mock, db_mock):
ml = MyLib()
api_mock.return_value = 'foo'
assert ml.caller() == 'foo'