我想测试以下方法:
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';
}
}
我无法测试此类,因为所有内容都是私有的,所有不同的操作都基于一个输入。
测试这个的正确方法是什么?
答案 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
的实际行为仅在该类的另一个单元测试中进行测试。
还有另一种测试类型,您希望测试单元之间的交互,集成测试。对于这样的测试,你不会模仿协作者,但你也不会测试内部,比如调用私有方法,但是例如测试实际写入数据库的内容。