Вымыть метод в том же тестируемом классе

Я хочу высмеять метод в том же классе, который тестирую.

ClassA {
   function hardToTest($arg) {
      // difficult to test code
   }

   function underTest() {
      return $this->hardToTest('foo');
   }
}

Я думал, что могу использовать рефлексию для этого, но, возможно, это просто знак того, что я должен переместить hardToTest в другой объект.

Ответы

Ответ 1

Этот тест будет успешным, если underTest() пройдет 'foo' до hardToTest(). Это называется частичным макетом в документации PHPUnit, потому что вы издеваетесь только над некоторыми из методов.

ClassATest {
    function testUnderTest() {
        $mock = $this->getMock('ClassA', ['hardToTest']);
        $mock->expects($this->once())
             ->method('hardToTest')
             ->with('foo');
        $mock->underTest();
    }
}

Я согласен с вашими инстинктами в том, что эта потребность может быть запахом кода, говорящим вам, что этот класс делает слишком много.

PHPUnit 5.4 +

Так как getMock() устарел в 5.4, используйте getMockBuilder() вместо:

$mock = $this->getMockBuilder('ClassA')
             ->setMethods(['hardToTest'])
             ->ge‌​tMock();

Ответ 2

В чем именно причина того, какой метод трудно тестировать?

Если метод защищен, вы можете просто расширить свой ClassA и сделать hardToTest( $arg ) общедоступным.

Суть в том, что вы не должны изменять класс только потому, что вам нужно написать unittest для него.

Ответ 3

Я прибегал к созданию подкласса моей тестируемой системы с использованием соответствующего метода.