Skip to content

Instantly share code, notes, and snippets.

@mapsi
Last active December 23, 2015 10:49
Show Gist options
  • Save mapsi/6624310 to your computer and use it in GitHub Desktop.
Save mapsi/6624310 to your computer and use it in GitHub Desktop.
Testing model static methods in controller actions

Testing model static methods in controller actions

Imagine we have a model called Accounts which contains a static find() method.

class Accounts extends MyModel
{
    public static function find($param)
    {
        // ...
    }

}

Unless you're using a PHP framework built for testing like Laravel, testing this method from within a controller action can be a quite frustrating thing to do.

class AuthController extends MyController
{
    public function loginAction()
    {
        // ...
        
        $account = Accounts::find(array('username'=> $username));
        
        $result = $account->validate($password);
        
        // ...
    }
}

How on earth can you test this?

Let's set up our PHPUnit_Framework_TestCase

class AuthControllerTest extends PHPUnit_Framework_TestCase
{

    public function testSomeAssertionShouldBeTrue()
    {
        $accounts = $this->getMock('\Accounts', array('validate', 'find'));
        $accounts->expects($this->once())->method('validate')->will($this->returnValue(true));
        // The following line set the static method expectations
        $accounts::staticExpects($this->any())->method('find')->will($this->returnValue($accounts));
        
        $controller = new AuthController();
        $result = $controller->loginAction();
        $this->assertTrue($result);
        // Hold on! How do it get the mock object in the action?!?
    }

It might not be as hard as you might think! (If you're willing to do a bit refactoring…)

class AuthController extends MyController
{
    private $model;
    
    public function getAccounts()
    {
        if (is_null($accounts)){
        $this->accounts = new Accounts();
    }
    
    public function setAccounts(Accounts $accounts)
    {
        $this->accounts = $accounts;
    }

    public function loginAction()
    {
        // ...
        
        $repo = $this->getAccounts();
        $account = $repo::find(array('username'=> $username));
        
        $result = $account->validate($password);
        
        // ...
    }
}

That's great news! This means we can inject the mocked object in our controller!

class AuthControllerTest extends PHPUnit_Framework_TestCase
{

    public function testSomeAssertionShouldBeTrue()
    {
        $accounts = $this->getMock('\Accounts', array('validate', 'find'));
        $accounts->expects($this->once())->method('validate')->will($this->returnValue(true));
        // The following line set the static method expectations
        $accounts::staticExpects($this->any())->method('find')->will($this->returnValue($accounts));
        
        $controller = new AuthController();
        // inject the mocked object in the controller
        $controller->setAccounts($accounts);
        
        $result = $controller->loginAction();
        $this->assertTrue($result);
        // Tada!
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment