4

我正在尝试测试一个管理数据库中数据访问的类(本质上是 CRUD)。我们使用的 DB 库恰好有一个 API,您首先通过静态调用获取表对象:

function getFoo($id) {
  $MyTableRepresentation = DB_DataObject::factory("mytable");
  $MyTableRepresentation->get($id);
  ... do some stuff
  return $somedata
}

...你明白了。

我们正在尝试测试此方法,但要模拟 DataObject 的东西,以便 (a) 我们不需要实际的数据库连接来进行测试,并且 (b) 我们甚至不需要包含 DB_DataObject 库来进行测试.

但是,在 PHPUnit 中,我似乎无法让 $this->getMock() 适当地设置静态调用。我有...

        $DB_DataObject = $this->getMock('DB_DataObject', array('factory'));

...但测试仍然显示未知方法“工厂”。我知道它正在创建对象,因为在它说找不到 DB_DataObject 之前。现在可以了。但是,没有办法吗?

我真正想做的是有两个模拟对象,一个也用于返回的表对象。所以,我不仅需要指定 factory 是一个静态调用,还需要它返回一些我已经设置的指定的其他模拟对象。

我应该提醒一下,我不久前在 SimpleTest 中做过这个(找不到代码)并且效果很好。

是什么赋予了?

[更新]

我开始明白它与expects()有关

4

6 回答 6

2

我同意你们俩的观点,最好不要使用静态调用。但是,我想我忘了提到 DB_DataObject 是第三方库,静态调用是他们代码使用的最佳实践,而不是我们的。还有其他方法可以使用它们的对象,包括直接构造返回的对象。它只是将那些该死的 include/require 语句留在使用该 DB_DO 类的任何类文件中。这很糟糕,因为如果你同时试图在你的测试中模拟一个同名的类,测试将会中断(或者只是不被隔离)——至少我认为。

于 2008-12-06T15:53:45.507 回答
2

当您无法更改库时,请更改您对它的访问权限。将所有对 DB_DataObject::factory() 的调用重构为代码中的实例方法:

function getFoo($id) {
  $MyTableRepresentation = $this->getTable("mytable");
  $MyTableRepresentation->get($id);
  ... do some stuff
  return $somedata
}

function getTable($table) {
  return DB_DataObject::factory($table);
}

现在您可以使用您正在测试的类的部分模拟,并让 getTable() 返回一个模拟表对象。

function testMyTable() {
  $dao = $this->getMock('MyTableDao', array('getMock'));
  $table = $this->getMock('DB_DataObject', ...);
  $dao->expects($this->any())
      ->method('getTable')
      ->with('mytable')
      ->will($this->returnValue($table));
  $table->expects...
  ...test...
}
于 2010-07-19T22:20:36.790 回答
1

这是代码中依赖关系的一个很好的例子 - 设计使得无法注入 Mock 而不是真正的类。

我的第一个建议是尝试重构代码以使用实例而不是静态调用。

于 2008-12-05T16:44:22.753 回答
0

DB_DataObject 类中缺少(或没有?)的是在调用工厂方法之前传递准备好的数据库对象的设置器。这样,如果需要,您可以传递一个模拟或自定义数据库对象(具有相同的接口)。

在您的测试设置中:

 public function setUp() {
      $mockDb = new MockDb();
      DB_DataObject::setAdapter($mockDb);
 }

factory() 方法应该返回模拟的数据库实例。如果它尚未集成到您的类中,您可能还必须重构 factory() 方法以使其工作。

于 2008-12-05T17:04:42.960 回答
0

您是否需要/在测试用例中包含 DB_DataObject 的类文件?如果在 PHPUnit 尝试模拟对象之前该类不存在,您可能会收到类似这样的错误。

于 2008-12-08T21:11:48.920 回答
0

使用 PHPUnit MockFunction 扩展和 runkit,您还可以模拟静态方法。小心,因为它是猴子补丁,因此只能在极端情况下使用。不能替代良好的编程实践。

https://github.com/tcz/phpunit-mockfunction

于 2011-06-09T20:48:05.650 回答