Testing that one class method calls another

1.5k views Asked by At

Imagine I have the following class.

class SomeClass {

    public function shortcutMethod($arg1) {
        return $this->method($arg1, 'something');
    }

    public function method($arg1, $arg2) {
        // some stuff
    }

}

So the shortcutMethod is a shortcut to the other method. Let us say I want to write a test that given and $arg1 the shortcutMethod will correctly call method with the correct arguments.

So far I think I figured I need to mock the class to expect a call to method with some arguments and then call shortcutMethod on the mock object like so (note I am using Mockery).

$mock = m::mock("SomeClass");
$mock = $mock->shouldReceive('method')->times(1)->withArgs([
    'foo',
    'something'
]);

$mock->shortcutMethod('foo');

This results in an exception like so shortcutMethod() does not exist on this mock object.

Did I misunderstand the usage for mocking? I understand it makes more sense for objects that are dependency injected into the class, but what in this scenario? How would you go about it? And perhabs more importantly, is this sort of testing useless, and if so, why?

1

There are 1 answers

0
Drumbeg On BEST ANSWER

You should use mocking to mock out the dependencies of the class under test, not the class under test itself. After all, you are trying to test the real behavior of your class.

Your example is a little basic. How you would test such a class would depend on what your method function does. If it returns a value that is in turn returned by shortCutMethod then I would say that your should just be asserting the output of shortCutMethod. Any dependencies within the method function should be mocked (methods belonging to other classes). I'm not that familiar with mockery, but I've given a tweaked version of your example a go.

class SomeClass {

   private $dependency;

   public function __construct($mockedObject) {
      $this->dependency = $mockedObject;
   }

   public function shortcutMethod($arg1) {
      return $this->method($arg1, 'something');
   }

   public function method($arg1, $arg2) {
      return $this->dependency->mockedMethod($arg1, $arg2);
   }

}

$mock = m::mock("mockedClass");

$mock->shouldReceive('mockedMethod')->times(1)->withArgs([
   'foo',
   'something'
])->andReturn('returnedValue');

$testCase = new SomeClass($mock);

$this->assertEquals(
   'returnedValue',
   $testCase->shortcutMethod('foo')
);

Having said that, it is possible to partially mock your class under test so that you can test the real behavior of the shortCutMethod function but mock out the method function to assert that it is called with the expected arguments. Have a look at partial mocks.

http://docs.mockery.io/en/latest/reference/partial_mocks.html