我是一个单元测试初学者,似乎一直坚持如何对包含内部函数调用的函数进行单元测试。例如,测试以下内容:
public function getBlueFooCount($fooId) {
$foo = $fooDao->getFoosById($fooId);
// custom logic to pull out the blue foos from result set
// custom count business logic on blue foos ...
return $count;
}
我如何能够模拟内部函数检索的内容?这是因为函数耦合太紧,需要放松吗?
答案 0 :(得分:2)
你需要模仿$fooDao
。希望有一个setter或一个DI容器,你不是用new
创建的(在这种情况下,它可能会紧密耦合。)
答案 1 :(得分:1)
为了构建@ aib的答案,当我们开始对遗留代码库进行单元测试时,我们的大多数类都是紧密耦合的,并且许多方法本身都在实例化新对象。虽然我们已经采取措施实施Dependency Injection和Inversion of Control,但我们仍然遇到了数百个仍需要进行单元测试的课程。
在为遗留方法编写单元测试时,我们重构并将实例化拉出到一个新的小方法,然后我们可以存根。不是最好的模式,但它很便宜并且无需进行更大规模的重构即可完成工作。
class FooCounter {
public function getFooDao(){
return new FooDao();
}
public function getBlueFooCount($fooId) {
/* was this
$fooDao = new FooDao();
*/
$foo = $this->getFooDao()->getFoosById($fooId);
// custom logic to pull out the blue foos from result set
// custom count business logic on blue foos ...
return $count;
}
}
class FooCounterTest extends PHPUnit_Framework_TestCase {
public function test_getBlueFooCount(){
$fooCounter = $this->getMock('FooCounter', array('getFooDao'));
$fooCounter->expects($this->any())
->method('getFooDao')
->will($this->returnValue(new MockFooDao()));
$this->assertEquals(0, $fooCounter->getBlueFooCount(1));
}
}
如果我们正在实现一个新类,我们通常使用基于构造函数的DI,如果你要创建新的东西,我将给出答案。这是其他人的链接,因为我相信之前已经说过更好(有点干):Dependency Injection and Unit Testing。以及针对您的案例的每个例子:
基于构造函数的注入
class FooCounter {
private $_fooDao
public function __construct($fooDao){
$this->_fooDao = $fooDao
}
public function getBlueFooCount($fooId) {
$foo = $this->_fooDao->getFoosById($fooId);
// custom logic to pull out the blue foos from result set
// custom count business logic on blue foos ...
return $count;
}
}
class FooCounterTest extends PHPUnit_Framework_TestCase {
public function test_getBlueFooCount(){
$fooCounter = new FooCounter(new MockFooDao());
$this->assertEquals(0, $fooCounter->getBlueFooCount(1));
}
}
基于Setter的注射
class FooCounter {
private $_fooDao
public function setFooDao($fooDao){
$this->_fooDao = $fooDao
}
public function getBlueFooCount($fooId) {
$foo = $this->_fooDao->getFoosById($fooId);
// custom logic to pull out the blue foos from result set
// custom count business logic on blue foos ...
return $count;
}
}
class FooCounterTest extends PHPUnit_Framework_TestCase {
public function test_getBlueFooCount(){
$fooCounter = new FooCounter();
$fooCounter->setFooDao(new MockFooDao());
$this->assertEquals(0, $fooCounter->getBlueFooCount(1));
}
}