Mocking a repository [duplicate] - unit-testing

This question already exists:
How to mock a repository
Closed 8 years ago.
I am trying to mock a repository in symfony 2, so that I can work on a test data. The problem is that the entity manager returns empty entity object, with all values as NULL, as if it's from the real database. What's wrong here? This is the code I've written so far:
$user = $this->getMock('\Acme\AdminBundle\Entity\Users');
$user->expects($this->once())
->method('getId')
->will($this->returnValue(1));
$user->expects($this->once())
->method('getEmail')
->will($this->returnValue('aaa'));
$userRepository = $this->getMockBuilder('\Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock();
$userRepository->expects($this->once())
->method('find')
->will($this->returnValue($user));
$entityManager = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager')
->disableOriginalConstructor()
->getMock();
$entityManager->expects($this->once())
->method('getRepository')
->will($this->returnValue($userRepository));
var_dump($entityManager->getRepository('Acme:Users')->find(1)); die();

When you Mock an object like that, using var_dump won't work. Read this tutorial for a full explanation of mocking. Another good explanation is the PHPUnit documentation itself. Here's the relevant information to note:
By default, all methods of the original class are replaced with a dummy implementation that just returns null (without calling the original method). Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.
Think of your mocked entity as an entity that behaves like your User, except every variable and every function is null. That is why you had to stub individual methods to return the values that you wanted - however, they only return those values when you call those functions directly. So, everything is absolutely correct in your Mocking. If you do:
var_dump($theUser->getId());
var_dump($theUser->getEmail());
You will get the following result:
int(1)
string(3) "aaa"
This is correct - it is exactly what you Mocked. So if you wanted to add an assertion you could do this (after removing the var_dump calls):
$this->assertSame(1, $theUser->getId());
$this->assertSame("aaa", $theUser->getEmail());
Note that those 2 tests wouldn't be very useful on their own because you'd essentially just be testing that PHPUnit itself works. The point of your Mocks would be in combination with some other methods that rely on a user being fetched from the database and having a particular id or email value.

Related

How to mock parameterized method in codeception framework

I have one parameterized method which accept string parameter and returns data upon passed param. I am using codeception framework for writing unit testing for php-zend project.
Method: getDataByView($view) $view can be default, all.
So I want mock this method such way it behave & return result based on passed params. I didnt get way in codeception framework so used phpunit code for that. But getting problems in that.
$map = array(
array('default', $default),
array('all', $all)
);
$mock = $this->getMockBuilder('ViewTable')
->setMethods(['getDataByView'])
->disableOriginalConstructor()
->getMock();
$mock->expects($this->any())
->method('getDataByView')
->will($this->returnValueMap($map));
Actually this code work as per my expectation. Since I am using setMethods() it calls the ViewTable class constructor. If I dont use setMethods then It doesn't call constructor.
Problems:
I want to mock only one method of class, so I have used
setMethods() but it calls mock class constructor. I dont want that.
How can it be solved in phpunit.
How to mock parameterized method in codeception framework.

Mocks vs Stubs in PHPUnit

I know stubs verify state and the mocks verify behavior.
How can I make a mock in PHPUnit to verify the behavior of the methods? PHPUnit does not have verification methods (verify()), And I do not know how to make a mock in PHPUnit.
In the documentation, to create a stub is well explained:
// Create a stub for the SomeClass class.
$stub = $this->createMock(SomeClass::class);
// Configure the stub.
$stub
->method('doSomething')
->willReturn('foo');
// Calling $stub->doSomething() will now return 'foo'.
$this->assertEquals('foo', $stub->doSomething());
But in this case, I am verifying status, saying that return an answer.
How would be the example to create a mock and verify behavior?
PHPUnit used to support two ways of creating test doubles out of the box. Next to the legacy PHPUnit mocking framework we could choose prophecy as well.
Prophecy support was removed in PHPUnit 9, but it can be added back by installing phpspec/prophecy-phpunit.
PHPUnit Mocking Framework
The createMock method is used to create three mostly known test doubles. It's how you configure the object makes it a dummy, a stub, or a mock.
You can also create test stubs with the mock builder (getMockBuilder returns the mock builder). It's just another way of doing the same thing that lets you to tweak some additional mock options with a fluent interface (see the documentation for more).
Dummy
Dummy is passed around, but never actually called, or if it's called it responds with a default answer (mostly null). It mainly exists to satisfy a list of arguments.
$dummy = $this->createMock(SomeClass::class);
// SUT - System Under Test
$sut->action($dummy);
Stub
Stubs are used with query like methods - methods that return things, but it's not important if they're actually called.
$stub = $this->createMock(SomeClass::class);
$stub->method('getSomething')
->willReturn('foo');
$sut->action($stub);
Mock
Mocks are used with command like methods - it's important that they're called, and we don't care much about their return value (command methods don't usually return any value).
$mock = $this->createMock(SomeClass::class);
$mock->expects($this->once())
->method('doSomething')
->with('bar');
$sut->action($mock);
Expectations will be verified automatically after your test method finished executing. In the example above, the test will fail if the method doSomething wasn't called on SomeClass, or it was called with arguments different to the ones you configured.
Spy
Not supported.
Prophecy
Prophecy is now supported by PHPUnit out of the box, so you can use it as an alternative to the legacy mocking framework. Again, it's the way you configure the object makes it becomes a specific type of a test double.
Dummy
$dummy = $this->prophesize(SomeClass::class);
$sut->action($dummy->reveal());
Stub
$stub = $this->prophesize(SomeClass::class);
$stub->getSomething()->willReturn('foo');
$sut->action($stub->reveal());
Mock
$mock = $this->prophesize(SomeClass::class);
$mock->doSomething('bar')->shouldBeCalled();
$sut->action($mock->reveal());
Spy
$spy = $this->prophesize(SomeClass::class);
// execute the action on system under test
$sut->action($spy->reveal());
// verify expectations after
$spy->doSomething('bar')->shouldHaveBeenCalled();
Dummies
First, look at dummies. A dummy object is both what I look like if you ask me to remember where I left the car keys... and also the object you get if you add an argument with a type-hint in phpspec to get a test double... then do absolutely nothing with it. So if we get a test double and add no behavior and make no assertions on its methods, it's called a "dummy object".
Oh, and inside of their documentation, you'll see things like $prophecy->reveal(). That's a detail that we don't need to worry about because phpspec takes care of that for us. Score!
Stubs
As soon as you start controlling even one return value of even one method... boom! This object is suddenly known as a stub. From the docs: "a stub is an object double" - all of these things are known as test doubles, or object doubles - that when put in a specific environment, behaves in a specific way. That's a fancy way of saying: as soon as we add one of these willReturn() things, it becomes a stub.
And actually, most of the documentation is spent talking about stubs and the different ways to control exactly how it behaves, including the Argument wildcarding that we saw earlier.
Mocks
If you keep reading down, the next thing you'll find are "mocks". An object becomes a mock when you call shouldBeCalled(). So, if you want to add an assertion that a method is called a certain number of times and you want to put that assertion before the actual code - using shouldBeCalledTimes() or shouldBeCalled() - congratulations! Your object is now known as a mock.
Spies
And finally, at the bottom, we have spies. A spy is the exact same thing as a mock, except it's when you add the expectation after the code - like with shouldHaveBeenCalledTimes().
https://symfonycasts.com/screencast/phpspec/doubles-dummies-mocks-spies

Asserting a changed state on a mocked object

I would like to unit test a function that takes a certain object as input,
processes it and when it finished, the state of that object should have been changed to a certain value.
As I want to do "real" unit testing (as I understand it), I only want to use the class that is providing the processing function,
and mock all other classes used.
To fulfill this requirement I need to mock the object that is being processed; but when it is only a mock, it has no real state anymore that could be changed.
Example pseudocode:
object = createMock('SomeClassName');
object.whenReceives('getState').shouldReturn(0);
Processor.process(object);
assertEquals(expected = 1, actual = object.getState());
The problem is that I need to mock the "getState" method to prepare the starting state for the test, and so
afterwards I cannot use the real method anymore.
Do you know how can I achieve this, or how I should change the design of the test?
PS: I am actually using PHPUnit and Mockery.
Thank you for any advice.
You are not deal with real object so you don't ask to the object the changed value but you can assert that someone dial with it for change the state. As Example:
$mock = Mockery::mock($class);
// Check that someone call the getstate method only one time
$mock
->shouldReceive('getState')
->once()
->andReturn(0);
// Check that someone call change the state method
$mock
->shouldReceive('setState')
->once()
->with(1);
Further reference:
http://code.tutsplus.com/tutorials/mockery-a-better-way--net-28097
http://culttt.com/2013/07/22/getting-started-with-mockery/
hope this help

Symfony2: Mocked service is set in the container but not used by the controller (it still uses the original service)

I'm writing the functional tests for a controller.
It uses a class to import some data from third party websites and to do this I wrote a class that I use into Symfony setting it a service.
Now, in my functional tests, I want to substitute this service with a mocked one, set it in the container and use it in my functional tests.
So my code is the following:
// Mock the ImportDataManager and substitute it in the services container
$mockDataImportManager = $this->getMockBuilder('\AppBundle\Manager\DataImportManager')->disableOriginalConstructor()->getMock();
$client->getContainer()->set('shq.manager.DataImport', $mockDataImportManager);
$client->submit($form);
$crawler = $client->followRedirect();
As I know that between each request the client reboots the kernel and I have to set again the mocked class, I set the mock immediately before the calling to $client->submit.
But this approach seems not working for me and the controller still continue to use the real version of the service instead of the mocked one.
How can I use the mocked class to avoid to call the remote website during my functional test?
If I dump the set mocked service, I can see it is correctly set:
dump($client->getContainer()->get('shq.manager.DataImport'));die;
returns
.SetUpControllerTest.php on line 145:
Mock_DataImportManager_d2bab1e7 {#4807
-__phpunit_invocationMocker: null
-__phpunit_originalObject: null
-em: null
-remotes: null
-tokenGenerator: null
-passwordEncoder: null
-userManager: null
}
But it is not used during the $form->submit($form) call and, instead, is used the original service.
UPDATE
Continuing searching for a solution, I landed on this GitHub page from the Symfony project, where a user asks for a solution to my same problem.
The second call doesn't use the mocked/substituted version of his class, but, instead, the original one.
Is this the correct behavior? So, is it true that I cannot modify the service container on a second call to the client?
Yet, I don't understand why the service is not substituted in the container and I haven't a real solution to that problem.
Anyway I found some sort of workaround, in reality more correct as solution (also if it remains unclear why the service is not substituted and this is a curiosity I'd like to solve - maybe because the $client->submit() method uses the POST method?).
My workaround is a simple test double.
I create a new class in AppBundle/Tests/TestDouble and called it DataImportManagerTestDouble.php.
It contains the unique method used by the controller:
namespace AppBundle\Tests\TestDouble;
use AppBundle\Entity\User;
class DataImportManagerTestDouble
{
public function importData(User $user)
{
return true;
}
}
Then, I instantiate it in the config_test.yml (app/config/config_test.yml) file in the following way:
services:
shq.manager.DataImport:
class: AppBundle\Tests\TestDouble\DataImportManagerTestDouble
This way, during the tests, and only during the tests, the class loaded as service is the TestDouble and not the original one.
So the test pass and I'm (relatively) happy. For the moment, at least.

How do I access overloaded properties on a PHPUnit mock object?

When mocking an object with PHPUnit, how do I access properties of the object which are normally accessed via overloading, i.e. via __get()?
For example, in the code below I am testing a Post object. Each Post has an author, which of type Role. Each Role has a Signature property.
$author = $this->getMockBuilder('App_Model_Domain_Role')
->disableOriginalConstructor()
->getMock();
$author->expects($this->any())
->method('__get')
->will($this->returnValue('authorname'));
As you can see I mock the Role object, then configure it to return a string ('authorname') when __get() is called. The Post object which I am testing refers to $this->author->signature. I am expecting it to return 'authorname', but instead the test errors out saying that $signature is an undefined property.
I tried configuring the mock as above but without the method() call (thinking that the expects() and will() calls would then apply to all the mock's methods) but still no success.
Any ideas?
Also, if you know of a good tutorial on PHPUnit mocks I'd be keen to see it - the manual seems to assume prior testing knowledge in this particular area.
I tried the same code as you and it is working for me. My PHPUnit version is 3.7.12. Which version are you using? If you are running a older version you could try upgrading.
public function testMockingMagicGetter()
{
$myMock = $this->getMockBuilder('MyClass')
->disableOriginalConstructor()
->getMock();
$myMock
->expects($this->any())
->method('__get')
->will($this->returnValue('authorname'));
var_dump($myMock->signature);
var_dump($myMock->dummy);
var_dump($myMock->someprop);
}
Results in:
string(10) "authorname"
string(10) "authorname"
string(10) "authorname"