如果我们有以下使用Builder设计模式的类:
class CourseListingBuilder extends Component
{
/**
* @var yii\db\Query
*/
private $query;
private $data = [];
public function init()
{
parent::init();
$this->query = new yii\db\Query();
}
/**
* Return a new instance of the builder
* @return CourseListingBuilder
*/
public static function create()
{
return new CourseListingBuilder();
}
public function selectColumns(array $columns)
{
// @TODO validate and format $columns
$this->query->select($columns);
return $this;
}
public function applyFilters($filters = [])
{
// @TODO validate and parse filters
$this->query->andWhere($filters);
return $this;
}
public function build()
{
// Make the actual DB query
$this->data = $this->query->all();
}
public function getData()
{
return $this->data;
}
}
我们这样使用它:
$data = CourseListingBuilder::create()
->selectColumns(['id', 'name'])
->applyFilters(['active'=>1])
->build()
->getData();
随着时间的推移,这些类变得非常大,因为我们有多个开发人员正在开发它们。开发人员扩展了selectColumns()
或applyFilters()
,偶尔也会延迟代码中断。我们最近开始在公司中引入单元测试,我们希望制作符合上述模式的类 - 单元可测试,最好通过小型重构。
如何对上面的构建器设计模式类进行适当的单元测试,因为它内部依赖于yii\db\Query
(顺便说一句,它来自Yii2框架,但这与示例无关)。与该示例相关的是我们不想测试yii\db\Query
的内部行为。它来自框架。我们知道它正在发挥作用。换句话说 - 我们希望尽可能“模拟”它,同时有效地测试Builder类中的实际方法以及它们将如何影响结果。
要指出的第二点是我们知道如何编写单元测试。这个问题一般不是关于“如何编写单元测试”,而是“如何为与第三方DAO类具有内部依赖性的构建器类编写单元测试”。
答案 0 :(得分:1)
最简单的方法是用一些简单的类替换yii\db\Query
并在方法调用后测试其状态。
class MockQuery extends \yii\db\Query {
public $select;
public $selectOption;
public function select($columns, $option = null) {
$this->select = $columns;
$this->selectOption = $option;
}
// ...
}
class CourseListingBuilder extends \yii\base\Component {
private $query;
public function selectColumns(array $columns) {
// @TODO validate and format $columns
$this->query->select($columns);
return $this;
}
// ...
}
并测试:
public function testQuery() {
$builder = new CourseListingBuilder();
// use reflection to access private property
$reflection = new \ReflectionObject($builder);
$property = $reflection->getProperty('query');
$property->setAccessible(true);
$property->setValue($builder, new MockQuery());
$builder->selectColumns(['id', 'name']);
$query = $property->getValue($builder);
$this->assertSame(['id', 'name'], $query->select);
$this->assertNull($query->selectOption);
}