Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking the SUT itself

My question is about unit testing. Assume we have the class below;

class X
{
    public function p1(){
       //logic
       $a = $this->p2();
       //more logic
    }

    public function p2(){
       //even more logic
    }
}

When writing a unit test for p1 method, should I mock p2 method?

What I am thinking is that, the test that is written for p1 method should only execute and test the p1 method not p2. But in order to realize that I should get a mock of Class X and call p1 method on that mock instance like below.

$xMock = $this->getMockBuilder('\X')
    ->setMethods(array('p2'))
    ->getMock();

$xMock->expects($this->any())
    ->method('p2')
    ->will($this->returnValue($value));

$resultTobeAsserted = $xMock->p1();

Unfortunately doing that feels a little wrongish to me. I discussed the topic with my colleagues and it boiled down to how you define your SUT(system under test). If a tester considers the particular method that is being tested as the SUT, then other methods that are called from the SUT would seem as dependencies and naturally tester will want to mock them. On the other hand if tester considers the whole class as the SUT, then those method calls will become part of the test so there won't be any reason to mock them.

Is that conclusion correct? Which kind of thinking would yield more robust unit tests?

like image 425
grandbora Avatar asked Feb 01 '13 14:02

grandbora


2 Answers

When writing a unit test for p1 method, should I mock p2 method?

No.

You are calling a method on a class and you expects that things happen.

With mocking p2 you make exceptions on the implementation details on the class.

Unfortunately doing that feels a little wrongish to me.

I say the felling it spot on.

Which kind of thinking would yield more robust unit tests?

If you test the observable behaviors of a class you make sure that class still does what it was supposed to do when you change the implementation of the class. Thats robustness.

if you test one method and mock out part of the implementation of that method (the internal method call) then you test a specif implementation and if the test fails you don't know if the external behavior changed.


I've written about this in some more detail in:

The UNIT in unit testing.

which details a couple more points about why i think it's important to test behaviors and not methods.

In short

Unit testing, in PHP, is about testing the observable behaviors of a class!

Behaviors:

  • return values
  • calling other methods
  • modifying global state (writing to files, the db, $GLOBALS)

Test those things. Disregard implementation details.

like image 58
edorian Avatar answered Oct 01 '22 14:10

edorian


If a tester considers the particular method that is being tested as the SUT, then other methods that are called from the SUT would seem as dependencies and naturally tester will want to mock them.

If there are arguments that support this separation, the same arguments can be used to refactor the class into two classes and this is exactly what you should to then.

like image 21
Fabian Schmengler Avatar answered Oct 01 '22 16:10

Fabian Schmengler