どのようにユニットテストは、ORMを使用するアプリで行うのですか?
-
21-08-2019 - |
質問
私はユニットテストのさまざまな質問を通して見てきたが、特にこの質問に答えるものを見つけることができません。
私はこのように機能が含まれているいくつかのPHPのクラスを持ってます:
static function _setSuspended($Suspended, $UserID)
{
try {
$con = Propel::getConnection();
$c1 = new Criteria();
$c1->add(DomainsPeer::USERID,$UserID);
$update = new Criteria();
$update->add(DomainsPeer::SUSPENDED,$Suspended);
BasePeer::doUpdate($c1, $update, $con);
return true;
} catch(PropelException $e) {
return $e->getMessage();
}
}
私はORMとしてPropelのを使用しています。私は「モック」と「スタブ」と何ではないの作成についての話、様々なユニットテストのトピックを読んだが、私は特にあなたがどのように上記のような機能をテストするために告げる何かを見つけることができませんでした。
私はそれを呼び出すようにしたいと思うので、上記の機能をテストする必要があります。私の考えは同じようなものです。私はそれを呼び出す場合でも、それはORMとしてPropelのを使用し、ユニットテストの原則に従って、私は自分自身で各機能を分離する必要があります。
私はちょうどそれを行うための方法が表示されません。私はここで行方不明ですか?
解決
私はORMの構成がテストされることは決してありませんので、ORMをからかうことは私に自信を与えていないことがわかりました。オームズもユニットテストで偽の自信を与えることができ、距離の影響で、アクションがたくさんあります。データベースドライバをからかったり、データベースが私のコードが正しいことを私もはるかに高い信頼性を提供し、ORMをからかうほど硬い程度であるインメモリの代替を提供します。
SQLiteは、ユニットテストのための優れたインメモリデータベースです。これは、PDOサポートされているデータベースのリストにあります。 (PDOはPropel 1.3データベースドライバです。)あなたは、インメモリデータベースを使用したくない場合は、すでに書かれたPDOのモックを見つけることができるかもしれない。
他のヒント
これは私がすべてではPropelに精通し、PHPでのみ多少慣れていないんだという点で、一般的な答えがあります。基本的な答えは、依存性注入を使用することです。代わりにあなたのORMを直接参照するので、あなたが実際に使用するために、あなたのクラス/関数にラッパーを注入し、その後、その周りにラッパーを作成します。ユニットテストを行うには、あなたはORMへのインターフェイスではなく、あなたのメソッド呼び出しにラッパーからの応答を設定することができますしないラッパーの模擬または偽のバージョンを作成します。これは、ユニットあなたの機能をテストするとき、あなたがORMを考慮することができます。
私はsymfonyのの PHPUnitのプラグインを構築しながら、同じ問題に取り組むためにしようとしていました。私は Djangoのテストフレームワークのと同様に、それに近づいてしまいました - 別のデータベース/接続を使用して、すべてのテストの前にそれを破壊し、再構築
。私はまた、唯一のテストラン(またはテストが明示的にそれを指示した場合)での最初のテストの前にテスト・データベースを再構築して逃げることができたことがわかりました。他のテストの前に、それだけで少し物事をスピードアップするためにすべてのデータを削除します。
私は最近のテストについて Misko Heveryのブログを読んでいます。これは、このような状況をカバー。あなたは、DI(依存性注入)を使用する必要があると思います。
私も、このビットで自分自身を苦労しています、と私はまた、Propelのを使用します。
1の場合、あなたは「オブジェクト」クラスではなく、相手に「サスペンド」メソッドを移動することができます。とにかく、この特定の機能のために、あなたはこれを達成するための静的メソッドを使用する必要はありません。あなたのAPIは、次のようになります:
MyObjectPeer::retrieveByPK(1)->suspend();
これは、通常のユニットテスト方法によってテスト可能であろう。
それはあなたが実際にDBがテストに関与している必要があり、その後私の知る限り、実際にテストする必要があり、データベースの場合。私はltreeはを使用して、私の現在のプロジェクトで多くのことをPostGISに、私は私のテストに含めるよりも、DB他に依存モデル・ロジックのためのユニットテストを実行するための他の方法を考えることはできませんしています。
これは、ユニットテスト可能にすることはできませんハード依存性クラスのexempleあります。
私たちは、別のデータベースへの接続をテストすることができる可能性が、その後、それはもうユニットテストではありませんが、統合テストます。
私が考えるより良い代替はあなたが必要とするすべての異なる方法をラップし、その後、あなたはそれを模擬することができるようになりますQueryFactoryクラスを持つことです。
は、まず最初に、私は
インターフェイスを作成しますinterface iQueryFactory
{
function firstFunction($argument);
function secondFunction($argument, $argument2);
}
私たちが必要とするすべてのあなたのORMの要求にQueryFactory
class QueryFactory implements iQueryFactory
{
function firstFunction($argument)
{
// ORM thing
}
function secondFunction($argument, $argument2)
{
// ORM stuff
}
}
クエリ工場の注入とのビジネスlogiqueがあります。
class BusinessLogic
{
protected $queryFactory;
function __construct($queryFactoryInjection)
{
$this->queryFactory= $queryFactoryInjection;
}
function yourFunctionInYourBusinessLogique($argument, $argument2)
{
// business logique
try {
$this->queryFactory->secondFunction($argument, $argument2);
} catch (\Exception $e) {
// log
// return thing
}
// return stuff
}
}
モックの部分、私は私のexempleのモックフレームワークを使用していないことに注意してください(ところで、あなたが応答セッターを作成することができます)。
class QueryFactoryMock implements iQueryFactory
{
function firstFunction($argument)
{
if (is_null($argument))
{
throw new \Exception("");
}
else
{
return "succes";
}
}
function firstFunction($argument, $argument2)
{
// sutff
}
}
そして、最終的にはモック実装で、当社のビジネスロジックをテストするユニットテスト
class BusinessLogicTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
require_once "BusinessLogic.php";
}
public function testFirstFunction_WhenInsertGoodName()
{
$queryMockup = new QueryFactoryMock();
$businessLogicObject = new BusinessLogic($queryMockup);
$response = $businessLogicObject ->firstFunction("fabien");
$this->assertEquals($response, "succes");
}
public function testFirstFunction_WhenInsetNull()
{
$queryMockup = new QueryFactoryMock();
$businessLogicObject = new BusinessLogic($queryMockup);
$response = $businessLogicObject->firstFunction(null);
$this->assertEquals($response, "fail");
}
}