测试私有属性/方法

时间:2016-02-22 15:51:10

标签: php phpunit

我想测试以下方法:

public function getJSONData(ExtClass $ext) {
   $obj = new DataClass();
   $obj -> setData($ext -> something);
   $sendObj = new SendClass();
   $sendObj -> send($obj);
   echo $obj -> getJSONData();
}

该方法根据$ ext对象的参数生成一些JSON数据。我可以通过传递不同的ExtClass对象来测试它的输出,如下所示:

public function testGetJSONData() {
   $extObj = new ExtObject('aaa', 'bbb', 'ccc');
   $mObj = new MainClass();
   $jsonData = $mObj -> getJSONData($extObj);
   $this -> assertEquals(1, $jsonData -> d);
   // etc
}

但后来我无法测试路上发生的所有不同事情 - 数据库插入,结构创建等。

例如,假设我有以下DataClass类:

class DataClass {

   private $arr1;
   private $val2;

   public function setData($something) {
      $this -> _setArr();
      $this -> _setVal();
   }

   private function _setArr() {
      $this -> arr1 = array('fdfds');
   }

   private function _setVal() {
      $this -> saveToDatabaseSomething($this -> arr1 -> something);
      $this -> val1 = 'gfgdfgdfgfd';
   }

}

我无法测试此类,因为所有内容都是私有的,所有不同的操作都基于一个输入。

测试这个的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

您永远不需要测试私有属性和方法,如果您认为需要私有属性和方法,那么您的代码就不够可用。

  

测试路上发生的所有不同事情 - 数据库插入,创建的结构等

对于单元测试,你会模仿这些东西(参见:https://phpunit.de/manual/current/en/test-doubles.html

在您的情况下,您似乎需要模拟SendClass,这似乎做了一些外部的东西。但遗憾的是,您正在测试中的方法中创建它。将对象创建与对象使用分开是一种很好的做法,例如:

class ClassToTest
{
    private $sendObj;
    public function __construct(SendClass $sendObj)
    {
        $this->sendObj = $sendObj;
    }
    public function getJSONData(ExtClass $ext) {
       $obj = new DataClass();
       $obj -> setData($ext -> something);
       $this->sendObj -> send($obj);
       echo $obj -> getJSONData();
    }
}

然后你就可以这样编写单元测试:

public function testGetJSONData()
{
    $input = new ExtClass('something');
    $expectedSent = new DataClass('something');
    $expectedJson = "{'something':'something'}";

    $mockSendObj = $this->getMock(SendClass::class, ['send']);
    $mockSendObj->expects($this->once())
        ->method('send')
        ->with($expectedSent);
    $subject = new ClassToTest($mockSendObj);
    $actualJson = $subject->getJSONData($input);
    $this->assertEquals($expectedJson, $actualJson);
}

SendClass的实际行为仅在该类的另一个单元测试中进行测试。

还有另一种测试类型,您希望测试单元之间的交互,集成测试。对于这样的测试,你不会模仿协作者,但你也不会测试内部,比如调用私有方法,但是例如测试实际写入数据库的内容。