使用数据库进行Phpunit测试

20

我正在尝试使用PHPunit进行单元测试。

我在这里找到了一个非常好的教程http://blog.nickbelhomme.com/php/phpunit-training-course-for-free_282

但是我有些不明白如何去做。

我有一个用户模块,它维护有关用户的所有信息。还有一个函数save,可以将用户保存在数据库中。所以我有一个testFunction

public function testCanCreateUser()
{
    $userData = array(
        'userName'  =>  'User1',
        'firstName' =>  'Joey',
        'lastName'  =>  'Hendricks',
        'email'     =>  'Joey@hendricks.com',
        'password'  =>  'f$tfe8F'
    
    ); 
    $user = new Model_User($userData);
    $user->save();
     
}

第一次运行测试时,这将起作用,因为数据库为空。但是当我第二次运行测试时,它就不起作用了,因为我的系统不允许在数据库中有相同的用户。因此,为了解决这个问题,我必须在每次运行测试之前重新创建我的测试数据库。最好的方法是什么?

或者这个问题可以通过其他方式解决吗?

3个回答

27

如果你想测试你的业务逻辑:模拟Database类并返回假数据。

如果你想测试执行SQL语句的类(我认为你也可以测试,因为我想知道我的代码在后端真正的数据库中是否工作正常),这会有点复杂,但有办法解决:

  • 使用setUp()和tearDown()在运行测试之前获取数据的一致状态是编写基于数据库的单元测试的好方法。尽管手动编写大量自定义SQL可能有些麻烦。

  • 为了让生活变得更轻松,您可以查看DbUnit扩展,看看它是否适用于您的应用程序。

  • 如果你真的想深入理解单元测试数据库交互,最好阅读一下Sebastian Bergmanns PHPQA书中关于数据库单元测试的章节

  • 如果你的应用程序允许使用自定义数据库名称并自动设置所有表格,那么也可能将数据库设置好一次并添加大量测试数据,并在所有测试中使用该数据。但是请注意,一个测试不要依赖于由另一个测试编写的数据。


2
只是想知道你是怎么知道Sebastion Bergmann的书里有一篇好文章的,因为它还没有出版。但这仍然是一件复杂的事情。 - sanders

14

setUp()tearDown()方法中使用另一个空的数据库副本运行测试,但要小心不要像GitHub那样处理。

如果你正在使用一个好的数据库(例如没有MyISAM表的MySQL),则可以将测试包装在事务中,并在测试后回滚:

 function setUp() { $this->db->exec("BEGIN"); }
 function tearDown() { $this->db->exec("ROLLBACK"); }

缺点是无法测试使用事务的代码(除非您将其抽象化并使用保存点进行模拟,但这很有问题)。

理想情况下,您应该使用依赖注入,并在虚假数据库类上运行测试:

$fakedb = new DatabaseThatDoesntReallySaveThings();
$user = new Model_User($fakedb, $userData);
$user->save();
$this->assertTrue($fakedb->wasAskedToSaveUser());

1
(new PDO())->beginTransaction() 应该也可以在 Mariadb/mysql 数据库中正常工作。 - sridesmet

3
我认为你可以使用tearDown()方法清除你保存的数据。
protected $_user;

public function testCanCreateUser()
{
    ...

    $this->_user = new Model_User($userData);
    $this->_user->save();
}

public function tearDown()
{
    $this->_user->delete();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接