そのため、システム全体で次のコードを使用しています。私たちは現在ユニットテストを遡及的に書いています(私の主張がなかったよりも遅くなっています)が、これがどのようにテスト可能であるかわかりませんか?
public function validate($value, Constraint $constraint)
{
$searchEntity = EmailAlertToSearchAdapter::adapt($value);
$queryBuilder = SearcherFactory::getSearchDirector($searchEntity->getKeywords());
$adapter = new SearchEntityToQueryAdapter($queryBuilder, $searchEntity);
$query = $adapter->setupBuilder()->build();
$totalCount = $this->advertType->count($query);
if ($totalCount >= self::MAXIMUM_MATCHING_ADS) {
$this->context->addViolation(
$constraint->message
);
}
}
概念的には、これはどの言語にも適用できるはずですが、私はPHPを使用しています。このコードは、Search
オブジェクトに基づいてElasticSearchクエリオブジェクトを作成するだけで、EmailAlert
オブジェクトから作成されます。これらのSearch
とEmailAlert
は単なるPOPOです。
私の問題は、SearcherFactory
(静的メソッドを使用)や、SearcherFactory::getSearchDirector
からの結果を必要とするSearchEntityToQueryAdapter
をモックアウトする方法がわからないことです。 andSearch
インスタンス。メソッド内の結果から作成されたものを注入するにはどうすればよいですか?気づいていないデザインパターンがあるのでは?
助けてくれてありがとう!
いくつかの可能性があり、PHPでstatic
メソッドをモックする方法があります。私が使用した最良の解決策は AspectMock ライブラリで、composer =(静的メソッドをモックする方法は、ドキュメントからかなり理解できます)。
ただし、これは別の方法で修正する必要がある問題の直前の修正です。
クエリの変換を担当するレイヤーを単体テストしたい場合は、非常に簡単な方法で行うことができます。
現在、validate
メソッドはいくつかのクラスの一部であると想定しています。すべての静的呼び出しをインスタンス呼び出しに変換する必要がない非常に迅速な修正は、静的メソッドのプロキシとして機能するクラスを構築することです。これらのプロキシを、以前は静的メソッドを使用していたクラスに注入します。
class EmailAlertToSearchAdapterProxy
{
public function adapt($value)
{
return EmailAlertToSearchAdapter::adapt($value);
}
}
class SearcherFactoryProxy
{
public function getSearchDirector(array $keywords)
{
return SearcherFactory::getSearchDirector($keywords);
}
}
class ClassWithValidateMethod
{
private $emailProxy;
private $searcherProxy;
public function __construct(
EmailAlertToSearchAdapterProxy $emailProxy,
SearcherFactoryProxy $searcherProxy
)
{
$this->emailProxy = $emailProxy;
$this->searcherProxy = $searcherProxy;
}
public function validate($value, Constraint $constraint)
{
$searchEntity = $this->emailProxy->adapt($value);
$queryBuilder = $this->searcherProxy->getSearchDirector($searchEntity->getKeywords());
$adapter = new SearchEntityToQueryAdapter($queryBuilder, $searchEntity);
$query = $adapter->setupBuilder()->build();
$totalCount = $this->advertType->count($query);
if ($totalCount >= self::MAXIMUM_MATCHING_ADS) {
$this->context->addViolation(
$constraint->message
);
}
}
}
まず、これを個別のメソッドに分割することをお勧めします。
public function validate($value, Constraint $constraint)
{
$totalCount = QueryTotal($value);
ShowMessageWhenTotalExceedsMaximum($totalCount,$constraint);
}
private function QueryTotal($value)
{
$searchEntity = EmailAlertToSearchAdapter::adapt($value);
$queryBuilder = SearcherFactory::getSearchDirector($searchEntity->getKeywords());
$adapter = new SearchEntityToQueryAdapter($queryBuilder, $searchEntity);
$query = $adapter->setupBuilder()->build();
return $this->advertType->count($query);
}
private function ShowMessageWhenTotalExceedsMaximum($totalCount,$constraint)
{
if ($totalCount >= self::MAXIMUM_MATCHING_ADS) {
$this->context->addViolation(
$constraint->message
);
}
}
これにより、これら2つの新しいメソッドをパブリックにして、QueryTotal
とShowMessageWhenTotalExceedsMaximum
を個別にテストすることを検討できる状況になります。ここで実行可能なオプションは、実際にはElasticSearchのみをテストするため、実際にQueryTotal
を単体テストするにはnotです。 ShowMessageWhenTotalExceedsMaximum
の単体テストの記述は簡単で、ビジネスロジックを実際にテストするため、はるかに理にかなっています。
ただし、「validate」を直接テストする場合は、クエリ関数自体をパラメーターとして「validate」に渡すことを検討してください(デフォルト値は$this->QueryTotal
)を使用すると、クエリ関数をモックアウトできます。 PHP構文が正しいかどうかわからないので、正しくない場合は、「疑似コード」と読んでください:
public function validate($value, Constraint $constraint, $queryFunc=$this->QueryTotal)
{
$totalCount = $queryFunc($value);
ShowMessageWhenTotalExceedsMaximum($totalCount,$constraint);
}