JohnnyC
JohnnyC

Reputation: 1435

PHPUnit - Setter doesn't modify my mock

I use PHPUnit for my unit tests (Symfony2 app).

This is my method that I want test (simplified):

public function __construct(Email $email)
{
    $this->email = $email;
}
public function sendEmail()
{
    // Here, more logic and condition, it's simplified
    if ($this->email->getOk() === 1) {
        $this->email->setSendEmail(1);
    }

    return $this->email;
}

And my test:

$emailMock = $this->getMock(Email::class);
$emailMock->method('getOk')->will($this->returnValue(1));
$emailMock->method('setSendEmail')->will($this->returnArgument(0));

$email = new Email($emailMock);
$emailModified = $email->sendEmail();
var_dump($emailModified->getSendEmail()); // Returns NULL

My class Email is a Doctrine Entity (the setter and getter is inside) (an example of entity)

How can I test if my mock is hydrated by my class? I want to know if my method works by looking if my object is hydrated.


Edit

I try an other method :

   $object = $this->getMock(MyClass::class);
   $object->method('setPosition')->will(
            $this->returnCallback(
                $pos = function ($arg) {
                    return $arg;
                }
            )
        );

   $object->method('getPosition')->will($this->returnValue($pos));


    $method = new \ReflectionMethod(MyClass::class, 'testMethod');
    $method->setAccessible(true);
    $res = $method->invoke(new MyClass($object));

   var_dump($res->getPosition()) // Return inexploitable Closure

I would like that $object->getPosition() return 1 when I execute $object->setPosition(1) from my external class MyClass() that I test.

Upvotes: 3

Views: 3065

Answers (2)

Niklaus
Niklaus

Reputation: 991

Even later, and just a modification of what Matt did above:

$storage = null;
$mock    = $this->createMock(MyClass::class);

$mock->expects($this->any())->method('set')->willReturnCallback(
    function ($arg) use ($mock, &$storage) {
        $storage = $arg;

        return $mock;
    }
);

$mock->expects($this->any())->method('get')->willReturnCallback(
    function () use (&$storage) {
        return $storage;
    }
);

This allows to store the values "locally" within the test, and doesn't expect you to have visibility to the object properties.

$storage is sent in as a reference to edit the contents of the variable in the tests scope, not just callback's scope.

Upvotes: 0

Matt
Matt

Reputation: 1590

Late answer, but I ended up mocking getter and setter to be functional like such

    // Mock setter
    $exceptionEvent->expects($this->once())->method('setResponse')->willReturnCallback(
        function($arg) use ($exceptionEvent) {
            $exceptionEvent->response = $arg;
        }
    );
    // Mock getter
    $exceptionEvent->expects($this->once())->method('getResponse')->willReturnCallback(
        function() use ($exceptionEvent) {
            return $exceptionEvent->response;
        }
    );

The class I am testing takes $exceptionEvent and calls setResponse() on it. This solution works for me, I then make assertions against $exceptionEvent->getResponse() after I run it through said class.

Upvotes: 2

Related Questions