如何使用PHPUnit模拟和测试实例化对象的函数?

如何使用PHPUnit模拟和测试实例化对象的函数?

问题描述:

我想写一个函数,其目的是测试数据库连接。它所做的是实例化Database对象,尝试连接到数据库并返回结果。如何使用PHPUnit模拟和测试实例化对象的函数?

的伪代码看起来像这样

<?php 

function testDatabaseLogin() { 
    // Get the database connection information from a file 
    // ... 

    // Database is a class which stores the connection information passed, 
    // When its connect() method is invoked, it tries to connect. nothing fancy 
    $conn = new Database($host, $port, $username, $password); 
    return $conn->connect(); // TRUE on success, FALSE otherwise 
} 

?> 

此代码段是我的情况的简化版本,但应该足以说明我的问题。

我想知道我在本例中如何使用PHPUnit来模拟Database类。我要的是我可以

  1. 断言,当此函数实例Database是正确的
  2. 存根的Database控制connect()的参数,以返回TRUEFALSE,所以我并不需要真正尝试连接到一个真实的数据库

我搜索了四周,但我发现它似乎像PHPUnit Mock对象不以这种方式工作。任何帮助表示感谢。在底线,如果它有助于简化测试,则更改函数实现是可以接受的。

谢谢。

+0

不知道这是否有帮助,但我问了一个涉及嘲讽PDO连接的问题(https://stackoverflow.com/questions/46379109/testing-coverage-with-phpunit-and-pdo)。您可能需要验证参数的合理值,因为没有连接就无法检查它们实际上是否有效。 –

+0

@NigelRen感谢您的帮助。我认为我的情况与你的不同,因为你的'DBAccess'类接受'PDO'对象。所以你可以使用PHPUnit来模拟'PDO'对象并传递它。但在我的情况下,'数据库'对象是在函数内部实例化的,这意味着即使我有一个模拟对象,我也没有办法将它传递给它。所以我在想,如果PHPUnit不能处理这种情况,我应该尝试重构函数以使其可测试。 – user7509214

+0

我认为一般的共识是能够注入任何依赖以启用测试等,https://stackoverflow.com/questions/130794/what-is-dependency-injection提供了更多的细节。 –

有是我有时使用

<?php 
class MyClass 
{ 
    public function databaseLogin() { 
     $conn = $this->createDatabase(); 
      return $conn->connect(); // TRUE on success, FALSE otherwise 
     } 

    protected function createDatabase() { 
     new Database($host, $port, $username, $password); 
    } 
} 

然后,创建一个 “类下的测试”,扩展你的类一招:

class MyClassUnderTest extends MyClass 
{ 
    public function __construct($databaseMock) 
    { 
     $this->databaseMock = $databaseMock; 
     parent::__construct(); 
    } 
} 

,然后在测试:

class MySuperTest 
{ 
    public function testSomethingWitDatabase() 
    { 
     $databaseMock = $this->getMockBuilder(DataBase::class) 
      ->disableOriginalConstructor() 
      ->getMock(); 

     $classUnderTest = new MyClassUnderTest($databaseMock); 
     $this->assertTrue($classunderTest->databaseLogin()); 
    } 
} 

因此,您正在将您的Database对象实例化为一个方法,该方法被刚创建用于测试的类覆盖。

+0

无论如何,最好使用依赖注入来获取更多可测试的代码...... –