brainmonger
brainmonger

Reputation: 687

Stuck on writing PHPUnit getMock unit test

I'm admittedly very rusty with unit testing.

I have the following function in my Registration.php:

protected function _showModal($request) {
  if (Store::isUserSupported()) { 
    return false; 
  }
  return true;
}

I started writing the following test but I know I'm missing some key items:

public function testUserSupported() {

$mockStore = $this->getMockClass('Store', array('isUserSupported'));

$mockStore::staticExpects($this->once()) 
->method('isUserSupported')
            ->will($this->returnValue(true));

$mockStore::isUserSupported();

$plugin = $this->getMockBuilder('Registration')
            ->setMethods(array('_showModal'))
            ->disableOriginalConstructor()
            ->getMock();

$plugin = $this->getPublicClass($plugin);

$plugin->expects($this->once())
            ->method('_showTermsModal')
            ->will($this->returnValue(true));

}

The $mockStore part is getting called, but not sure how to tie it into my $plugin call.. I want to write a test to mock Store::isUserSupported() returning true within the showModal function. Any words of advice?

Upvotes: 0

Views: 3375

Answers (1)

Jose Armesto
Jose Armesto

Reputation: 13799

You should avoid static calls in your code, because they make your code coupled together and hard to change and hard to maintain. It also makes it harder to tests, as you are suffering here.

Instead of static calls, pass the collaborators needed to work. In your code example, the class you want to test would receive as parameter the Store class, instead of calling it statically.

By doing this change, you can now create a mock for the method isUserSupported() of the Store class, and pass the mock to the object under test, that will efectively use the mocked object.

$mockStore = $this->getMock('Store', array('isUserSupported'));

$mockStore->expects($this->once())
    ->method('isUserSupported')
    ->will($this->returnValue(true));

$object_under_test = new Registration( $mockStore );
$object_under_test->showModal($request); // Only in case showModal is public, otherwise call public method

If the Store class is only needed for that method, and you don't want to pass it as dependency in the constructor, you can pass it on the method itself.

$mockStore = $this->getMock('Store', array('isUserSupported'));

$mockStore->expects($this->once())
    ->method('isUserSupported')
    ->will($this->returnValue(true));

$object_under_test = new Registration();
$object_under_test->showModal($mockStore, $request); // Only in case showModal is public, otherwise call public method

Also, you shouldn't test protected/private methods of your classes, since they are low level implementation details that your tests don't need to know about. You should only make calls to public methods in your tests. Otherwise, the tests become very coupled with the real implementation, and if you refactor your code, you will most likely have to change the tests too.

Upvotes: 3

Related Questions