测试完全使用其他对象方法的方法

时间:2013-02-22 21:55:50

标签: php unit-testing testing phpunit

我在为它编写单元测试时重构一个类。 有一种情况是我的一个方法是完全调用另一个对象的方法,这些方法被注入到我正在测试的这个类中。

所以我必须模仿我注入课堂的对象。

现在,问题在于,是否值得为此特定方法编写单元测试? 编写单元测试似乎很奇怪,所有它都调用其他对象的方法,该对象本身必须被模拟,那为什么我要测试这个方法呢?

测试方法的目的不是检查方法的功能是否按预期工作? 如果是,那么当我嘲笑它所有的东西时,那个特定的方法没有什么可以测试那么我为什么要测试呢?

我真的很困惑!

我坚持的方法就是这个(用于自定义会话处理):

public function write($sessionId, $sessionData)
{
    $sth = $this->databaseConnection->prepare("INSERT INTO `{$this->DBTableName}` (`session_id`,`session_name`,`session_data`) VALUES(:session_id, :session_name, :session_data) ON DUPLICATE KEY UPDATE `session_data`=:session_data;");
    $sth->bindValue(':session_id', $sessionId);
    $sth->bindValue(':session_name', $this->sessionName);
    $sth->bindValue(':session_data', $sessionData);

    return $sth->execute();
}

这里也是这段代码的链接:http://pastebin.com/1FBeU6mb

顺便说一句,我刚开始为我的课程编写测试,而且我是测试领域的初学者,而且经验不足。

提前致谢。

3 个答案:

答案 0 :(得分:2)

我对php并不熟悉,但看起来你只是在构建和执行数据库查询,对吗?

除非此方法与数据库之间存在其他一些我无法看到的其他层,否则这里真的没有什么值得嘲笑的。因此,你在这里嘲笑不会给你带来很多价值。从某种意义上说,测试这种方法的价值有限,因为你实际上只是测试数据库层,我们通常可以假设它已经是正确和稳定的,因此不需要测试。

一般来说,模拟的价值在于它允许您通过假设其他方法正在做什么来简化测试,并允许您不必间接测试其他方法。

在选择测试写入方法时,您测试的结果是您已经采取了正确的步骤来返回正确的结果。就是这样。我不熟悉php模拟框架,但我知道其他语言的框架你可以设置所谓的期望,它允许你指定某个方法将使用某些参数调用某个对象。您甚至可以经常指定执行顺序。这里要说的是,您正在测试对象发送的传出消息,而不是这些消息的返回值。

由您自行决定是否对此测试所需的维护有价值。

答案 1 :(得分:0)

您正在测试是否将正确的参数传递给您准备好的语句。此外,您应该测试write方法是否返回准备好的语句结果。

如果您不对此进行测试,您的应用程序可能有多种方法可以解决。

  • 重命名或删除方法参数($sessionId$sessionData
  • 重新命名您的财产$this->sessionName
  • 删除其中一个bindValue来电。
  • 错误命名绑定别名。它们应与您的查询相符。
  • 返回除execute()
  • 的结果以外的其他内容

等。等

所以是的,测试这个是很好的实践。

答案 2 :(得分:0)

假设您的示例描述了一个SessionHandler类,它类似于:

class SessionHandler
{
    public function __construct($sessionTableName, $sessionName, \PDO $databaseConnection)
    { 
        $this->DBTableName = $sessionTableName;
        $this->sessionName = $sessionName;
        $this->databaseConnection = $databaseConnection;
    }

    // among others, your method write($sessionId, $sessionData) follows
}

这可以涵盖方法write()

public function testWriteInsertsOrUpdatesSessionData()
{
    /**
     * initialize a few explaining variables which we can refer to 
     * later when arranging test doubles and eventually act
     */
    $sessionTableName = 'sessions';
    $sessionName = 'foobarbaz';

    $sessionId = 'foo';
    $sessionData = serialize([
        'bar' => 'baz',
    ]);

    $executed = true;

    /**
     * create a test double for the statement that we expect to be returned 
     * from `PDO::prepare()`
     */
    $statement = $this->createMock(\PDOStatement::class);

    /**
     * set up expectations towards which methods should be invoked 
     * on the statement, specifying their order
     */
    $statement
        ->expects($this->at(0))
        ->method('bindValue')
        ->with(
            $this->identicalTo(':session_id'),
            $this->identicalTo(sessionId)
        );

    $statement
        ->expects($this->at(1))
        ->method('bindValue')
        ->with(
            $this->identicalTo(':session_name'),
            $this->identicalTo($sessionName)
        );

    $statement
        ->expects($this->at(2))
        ->method('bindValue')
        ->with(
            $this->identicalTo(':session_data'),
            $this->identicalTo(sessionData)
        );

    $statement
        ->expects($this->at(3))
        ->method('execute')
        ->willReturn($executed);

    /**
     * create a test double for the database connection we inject
     * into SessionHandler during construction
     */
    $databaseConnection = $this->createMock(\PDO::class);

    $databaseConnection
        ->expects($this->once())
        ->method('prepare')
        ->with($this->identicalTo(sprintf(
            'INSERT INTO `%s` (`session_id`,`session_name`,`session_data`) VALUES(:session_id, :session_name, :session_data) ON DUPLICATE KEY UPDATE `session_data`=:session_data;',
            $sessionTableName
        )))
        ->willReturn($statement);

    $sessionHandler = new SessionHandler(
        $sessionTableName,
        $sessionName,
        $databaseConnection
    );

    $result = $sessionHandler->write(
        $sessionId,
        $sessionData
    );

    $this->assertSame($executed, $result);
}

供参考,见: