-1

我有这样的代码:

protected function _checkUserVisibility()
{
    try {
        if (!$params->getUsrParametr(self::ACTIVE_FIF)) { // calling oracle stored proc
            throw new Unitex_Exception('ALARM');
        }
    }
    catch (Exception $e) {
        $this->logOut();
        throw $e;
    }
}

这个函数是从另一个函数调用的(依此类推)。

一个问题:如何对这部分代码进行工作单元测试?

编辑1:

首先采取 hehe http://framework.zend.com/manual/1.12/en/zend.test.phpunit.html 比改进(希望)测试过程是:

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase {
..........
public function testLoginAction()
{
    $request = $this->getRequest();
    $request->setMethod('POST')
        ->setHeader('X_REQUESTED_WITH', 'XMLHttpRequest')
        ->setPost(array(
                'user'     => 'test_user',
                'password' => 'test_pwd',
        ));

        $filialId = 1;
        $stmt1 = Zend_Test_DbStatement::createUpdateStatement();
        $this->getAdapter()->appendStatementToStack($stmt1);
        $this->getAdapter()->appendStatementToStack($stmt1);
        $this->getAdapter()->appendStatementToStack($stmt1);
        $this->getAdapter()->appendStatementToStack($stmt1);

        $stmt1Rows = array(array('IRL_ALIAS' => 'RO_COMMON', 'ISADM' => 'N'));
        $stmt1 = Zend_Test_DbStatement::createSelectStatement($stmt1Rows);
        $this->getAdapter()->appendStatementToStack($stmt1);

        $this->dispatch('/user/login');// <-- crash here
    $this->assertController('user');
    $this->assertAction('login');
    $this->assertNotRedirect();
    $this->_getResponseJson();
}
4

2 回答 2

4

在您的单元测试中,您绝对不需要任何数据库交互。您的问题的答案是使用 stub 进行 db 功能。

假设 $paramsSomeClasscontains的属性getUsrParametr,例如从数据库中获取某些内容。您正在测试_checkUserVisibility方法,因此您不关心SomeClass. 这样您的测试将如下所示:

class YourClass
{
    protected $params;

    public function __construct(SomeClass $params)
    {
        $this->params = $params;
    }

    public function doSomething()
    {
        $this->_checkUserVisibility();
    }

    protected function _checkUserVisibility()
    {
        try {
            if (!$this->params->getUsrParametr(self::ACTIVE_FIF)) { // calling oracle stored proc
                throw new Unitex_Exception('ALARM');
            }
        }
        catch (Exception $e) {
            $this->logOut();
            throw $e;
        }
    }
}

当然,单元测试您测试的唯一方法是公共方法,但是您可以通过测试公共方法来覆盖受保护的方法。

public function testDoSomethingAlarm()
{
    // set expected exception:
    $this->setExpectedException('Unitex_Exception', 'ALARM');

    // create the stub
    $params = $this->getMock('SomeClass', array('getUsrParametr'));

    // and set desired result
    $params->expects($this->any())
        ->method('getUsrParametr')
        ->will($this->returnValue(false));

    $yourClass = new YourClass($params);
    $yourClass->doSomething();
}

第二个测试 which test case ifgetUsrParametr将返回true

public function testDoSomethingLogout()
{
    // set expected exception:
    $this->setExpectedException('SomeOtherException');

    // create the stub
    $params = $this->getMock('SomeClass', array('getUsrParametr'));

    // set throw desired exception to test logout
    $params->expects($this->any())
        ->method('getUsrParametr')
        ->will($this->throwException('SomeOtherException'));

    // now you want create mock instead of real object beacuse you want check if your class will call logout method:   
    $yourClass = $this->getMockBuilder('YourClass')
        ->setMethods(array('logOut'))
        ->setConstructorArgs(array($params))
        ->getMock();

    // now you want ensure that logOut will be called
    $yourClass->expects($this->once())
        ->method('logOut');

    // pay attention that you've mocked only logOut method, so doSomething is real one
    $yourClass->doSomething();
}
于 2012-12-15T12:10:05.090 回答
2

如果您将 PHP 5.3.2+ 与 PHPUnit 一起使用,您可以在运行测试之前使用反射将它们设置为公共来测试您的私有和受保护方法,否则您可以通过正确测试公共方法来测试受保护/私有方法使用受保护/私有方法。一般来说,这两个选项中的后者通常是你应该如何做的,但如果你想使用反射,这里有一个通用的例子:

protected static function getMethod($name) {
  $class = new ReflectionClass('MyClass');
  $method = $class->getMethod($name);
  $method->setAccessible(true);
  return $method;
}

public function testFoo() {
  $foo = self::getMethod('foo');
  $obj = new MyClass();
  $foo->invokeArgs($obj, array(...));
  ...
}
于 2012-12-14T02:56:41.050 回答