使用私有方法正确测试一个简单的类

Rat*_*tty 3 php phpunit unit-testing symfony

描述: 我有一个简单的类,它创建一个指向上传文件目录的符号链接,这些文件仅供注册会员使用。它使用当前用户的会话 ID 为用户生成随机目录。一旦用户注销,符号链接就会被删除。我想对类的功能进行单元测试。

问题: 由于大多数函数都是私有的,而且我认为没有任何理由将它们公开,我该如何正确地对此类进行单元测试?

这是 PHP 类的代码:

<?php

namespace Test\BackEnd\MemberBundle\Library;


use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\KernelInterface;

class DirectoryProtector
{
/** @var SessionInterface $_session */
private $_session;

/** @var ContainerInterface $_kernel */
private $_kernel;

/**
 * @param SessionInterface $session
 * @param KernelInterface $kernel
 */
public function __construct( SessionInterface $session, KernelInterface $kernel )
{
    $this->_session = $session;
    $this->_kernel = $kernel;
}

/**
 * @param bool|false $protect
 * Public method to symlink directories
 */
public function protectDirectory($protect = FALSE)
{

    if ($protect) {
        if ( ! $this->doesDirectoryExists())
            symlink($this->getAppDir() . '/uploads', $this->getViewableSessionDirectory());
    } else {
        if ($this->doesDirectoryExists())
            unlink($this->getViewableSessionDirectory());
    }

}

/**
 * @return bool
 * Check to see if viewable session directory exists or not
 */
private function doesDirectoryExists()
{
    if (file_exists($this->getViewableSessionDirectory()))
        return TRUE;

    return FALSE;
}

/**
 * @return string
 * Get viewable session full directory path
 */
private function getViewableSessionDirectory()
{
    return $this->getAppDir() . '/../web/files/' . $this->getSessionId();
}

/**
 * @return string
 * Return app root directory
 */
private function getAppDir()
{
    return $this->_kernel->getRootDir();
}

/**
 * @return string
 * Return session id
 */
private function getSessionId()
{
    return $this->_session->getId();
}

}
Run Code Online (Sandbox Code Playgroud)

这是当前测试类的代码:

<?php

namespace Test\BackEnd\MemberBundle\Tests\Library;

use Test\BackEnd\MemberBundle\Library\DirectoryProtector;

class DirectoryProtectorTest extends \PHPUnit_Framework_TestCase
{

public function testProtectDirectory()
{
    //$this->markTestIncomplete("WIP on protect directory.");
    $request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')
        ->getMock();

    $container = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')
        ->getMock();

    /** @var DirectoryProtector $dp */
    $dp = $this->getMockBuilder('Test\BackEnd\MemberBundle\Library\DirectoryProtector')
            ->setConstructorArgs(array($request, $container))
            ->setMethods(array(
                'getViewableSessionDirectory',
                'getAppDir',
                'getSessionId'
            ))
            ->getMock();

    $dp->expects($this->once())
        ->method('doesDirectoryExists')
        ->will($this->returnValue(TRUE));

    $dp->protectDirectory(TRUE);

}

}
Run Code Online (Sandbox Code Playgroud)

Abs*_*dés 5

来自https://phpunit.de/manual/current/en/test-doubles.html

限制:final、private 和 static 方法

请注意,final、private 和 static 方法不能被存根或模拟。它们被 PHPUnit 的测试双重功能忽略并保留其原始行为。

对私有或受保护的方法进行单元测试不是一个好习惯。您应该测试公共API。私有方法应该通过 API 间接测试。也就是说,您可以使用反射使方法公开:

$instance = new DirectoryProtector(...);

$ref = new \ReflectionClass('DirectoryProtector');

$method = $ref->getMethod('doesDirectoryExists');
$method->setAccessible(true);

$this->assertTrue($method->invoke($instance));
Run Code Online (Sandbox Code Playgroud)