PHPunit:如何从外部函数更改模拟对象的专有性

时间:2019-05-28 09:13:07

标签: php symfony phpunit phpunit-testing

我正在使用Symfony,正在尝试在“ Student”类中测试addStudentCard函数,该函数向$ studentCards数组集合专有性中添加了一个“ StudentCard”对象,并向“ StudentCard”中的$ student专有性中添加了一个“ Student”对象。类。这是我的方法:

class StudentCard {
  private $student;
  public function getStudent();
  public function setStudent();
  //...
}

class Student {
  private $studentCards;
  public function getStudentCards();
  public function addStudentCard(StudentCard $studentCard){
    $studentCard->setStudent($this);
    $this->studentCards[] = $studentCard;
    return $this;
  //...
}

我想要实现的是使用MockBuilder测试此addStudentCard函数,我已经这样做了,而没有使用模拟:

class StudentTest extends AbstractTestCase {
  public function testAddStudentCard(){
    $studentCard = new StudentCard();
    $student = new Student();
    $student->addStudentCard($studentCard);
    $student->assertSame($studentCard, $student->getStudentCards()[0]);
    $student->assertSame($student, $studentCard->getStudent());
}

这按预期工作,没有问题。

我想要替换行:

$studentCard = new StudentCard();

具有这样的内容:

$studentCard = $this->getMockBuilder(StudentCard::class)->getMock();

但是我得到的是错误: 无法断言null与Student类的对象相同。

2 个答案:

答案 0 :(得分:0)

您的方案存在的问题是,您断言该模拟返回了原始学生:

$student->assertSame($student, $studentCard->getStudent());

如果$studentCard是Mock对象,除非您告诉它返回原始对象,否则它不会返回。但是,由于您已经在使用模拟,因此无需测试。

在这种情况下,您实际要测试的是将$student分配回了$studentCard。这就是expectations的目的。

因此,在您的特定情况下,您可以选择:

$studentCard->expects($this->once())->method('setStudent')->with($student);
// ...
$student->addStudentCard($studentCard);

在致电addStudentCard之前,请确保已在那行(如代码中所示),否则测试将失败,即未达到期望。

设置期望值后,无需在模拟对象上运行任何断言(并且不应这样做)。

答案 1 :(得分:0)

提供的答案 Ondrej Führer 是我所描述问题的正确答案
我还有一个removeStudentCard方法,该方法可从studentCard对象中删除该学生,因此$ this-> once()不适合我的情况。为了测试这一点,我做了一些修改,完全做到了 Ondrej Führer 的建议,因此我添加的代码行是:

$studentCard->expects($this->exactly(2))->method('setStudent')->withConsecutive(
    [$student],
    [null]
);
//...
$student->addStudentCard($studentCard);
//...
$student->removeStudentCard($studentCard);

这是自我解释,方法setContact预计将被两次调用,以$ student作为参数,而在第二次调用中为null。
希望这对希望做类似事情的人有所帮助。