Symfony Mock a specific method in my unit test - php

I have problem when trying to mock a service in order to unit test it.
in my test class I have,
$mock = $this->getMock('MyClass');
$mock->expects($this->any())->method('method_2')->will($this->returnValue('fake_value'));
in my service, method_2() calls another method (let's say method_1()')
As I want to unit test only method_1() I need to mock only method_2()
but when I am running this test, method_1() already returns null.
Do you have any idea on why I'm already getting null?

Take a look at getMock() helper signature, it allows you to pass an array of methods as a second argument, those methods are then mocked and returns null (unless you define the valus each one of them should return)
In your case all the methods are mocked and return null except method_2() for which you forced the returned value.
Try again and replace,
$mock = $this->getMock('MyClass');
by,
$mock = $this->getMock('MyClass', array('method_2'));

Related

How to mock based on method parameter

One of my stubbed mock objects has a method which will be called twice in a method that I want to test. How can I write the tests so that both branches in my test method will be coveraged? Code sample (The stubbed object is the cache):
public function myMethodToTest($param, $default) {
if ($this->cache->has($param)) {
return 'A';
} else if ($this->cache->has($default)) {
return 'B';
}
}
Lifted from the phpunit documentation, we can start with this example:
public function testObserversAreUpdated()
{
// Create a mock for the Observer class,
// only mock the update() method.
$observer = $this->getMockBuilder('Observer')
->setMethods(array('update'))
->getMock();
// Set up the expectation for the update() method
// to be called only once and with the string 'something'
// as its parameter.
$observer->expects($this->once())
->method('update')
->with($this->equalTo('something'));
// Create a Subject object and attach the mocked
// Observer object to it.
$subject = new Subject('My subject');
$subject->attach($observer);
// Call the doSomething() method on the $subject object
// which we expect to call the mocked Observer object's
// update() method with the string 'something'.
$subject->doSomething();
}
Pay attention to the with() method call. You can use that to specify an expectation that the method will be called with a specific parameter value and dictate what to return when it happens. In your case, you should be able to do something like this:
$cacheStub->method('has')
->with($this->equalTo('testParam1Value'))
->willReturn(true);
Do that in one test, and you'll test one branch of your code. In a separate test, you can set up the mock differently:
$cacheStub->method('has')
->with($this->equalTo('testParam2Value'))
->willReturn(true);
This test will test your other branch. You can combine them into a single test if you like, you may have to recreate the mock in between assertions.
See also this short article that has some alternative ways of calling with() other than $this->equalTo()

PHPUnit Mock multiple different methods

I'm new to Unit test and I'm experimenting with PHPUnit framework.
I have a function that calls two others function:
class Dummy{
public function dummyFunction(){
$this->anotherDummyFunction();
.....
$this->yetAnotherDummyFunction();
}
public function anotherDummyFunction(){
.....
}
public function yetAnotherDummyFunction(){
.....
}
}
I want test that the two functions be called when I invoke dummyFunction().
Here the test class:
class TestDummyClass {
public function testDummyFunction(){
$dummyClassMock = $this->getMockBuilder('Dummy')
->setMethods( array( 'anotherDummyFunction','yetAnotherDummyFunction' ) )
->getMock();
$dummyClassMock->expects($this->once())
->method( 'anotherDummyFunction' );
$dummyClassMock->expects($this->once())
->method( 'yetAnotherDummyFunction' );
$dummyClassMock->dummyFunction();
}
}
Now I've notice that if I mock the Dummy class in this way, the result is
Expectation failed for method name is equal to anotherDummyFunction
when invoked 1 time(s). Method was expected to be called 1 times,
actually called 0 times.
But If I set the Mock Object in this way
$dummyClassMock = $this->getMockBuilder('Dummy')
->setMethods( array( 'anotherDummyFunction' ) )
->getMock();
the test pass. Lastly, if I set the mock object with setMethods(null), the test fails again
It seems that I could pass an array with only one element, the method that I want check if is called. But I've seen here: https://jtreminio.com/2013/03/unit-testing-tutorial-part-5-mock-methods-and-overriding-constructors/ that setMethods is used for inject the return value of the method passed, so this wouldn't have an effect on the call itself, unless I put the dummyFunction in setMethods (In this case the function will return null without call the other two methods, and in this way yes, the test have to fail)
I've made something wrong? I've seen pieces of code where are more than one methods in setMethods()... Why the test fails if I put tho methods in setMethods?
Thanks
You are using $this->once(), which means that the test can only pass if the method is called exactly once – in every test case where the mock is used!
What you probably want is $this->any() which does not require the method to be called every time.

How to mock object properties?

I'm trying to mock properties but can't get it to work. In this case I'm trying to mock request property Symfony\Component\HttpFoundation\Request.
According to this answer I should return a value for __get
Following code keeps showing NULL:
$testRequest = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$testRequest->expects($this->any())
->method('__get')
->with($this->equalTo('request'))
->will($this->returnValue("working"));
var_dump($testRequest->request);
Maybe it's because the answer is too old so checking out the current documentation of mocking but that one doesn't mention how to mock properties at all.
According to another answer I can try the following:
private $post=array('search'=>'abc','start'=>null);
...
$paramBag = $this->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
->disableOriginalConstructor()
->getMock();
foreach($this->post as $key=>$value){
echo "setting:".$key.' with:'.$value.PHP_EOL;
$paramBag->expects($this->any())
->method('get')
->with($this->equalTo($key))
->will($this->returnValue($value));
}
$this->request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$this->request->request=$paramBag;
echo ($this->request->request->get('start'));
That gives me:
Expectation failed for method name is equal to <string:get> when invoked zero or more times
Parameter 0 for invocation Symfony\Component\HttpFoundation\ParameterBag::get('search', null, false) does not match expected value.
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'search'
+'start'
Is it not possible to override multiple methods with different values? Again, the documentation completely lacks any examples of that.
If I try echo ($this->request->request->get('start')); it will fail on expecting search but getting start. There is no way I can give it something that doesn't fail.
Trying to unit test but Symfony2 does not seem to have such a thing. Every documentation almost immediately skips unit testing with examples of ordinary classes needing no dependencies and then moves to functional testing. And some documentation flat out say unit testing for repositories is not recommended.
I would like to see if DQL statements are created correctly though and am left with no documented option to unit test this.
Can do this part by creating a fake Doctrine\ORM\EntityRepository class and include that file at the start of my test. Tried the same with Symfony\Component\HttpFoundation\Request but get a can't re define this class when trying to do that. Somehow when my test is loaded Symfony\Component\HttpFoundation\Request already is loaded.
Not entirely sure how you mean mock properties, I would assume properties are set via getters and setters and then you could just set them with whatever Mock you want.
If however you need to assign a mock object to a private /protected property for which you do not have an accessor method, you can do this:
$reflection = new \ReflectionClass($objectThatContainsThePropertyToMock);
$property = $reflection->getProperty($propertyName);
$property->setAccessible(true);
return $property->setValue($mockedObject);

phpunit testing method that calls other class methods which need mock

I'm trying to create a pretty standard unit test where I call a method and assert it's response, however the method I'm testing calls another method inside the same class which does a little bit of heavy lifting.
I want to mock that one method but still execute the method I'm testing as is, only with the mocked value returned from the call to the other method.
I've dumbed down the example to make it as simple as possible.
class MyClass
{
// I want to test this method, but mock the handleValue method to always return a set value.
public function testMethod($arg)
{
$value = $arg->getValue();
$this->handleValue($value);
}
// This method needs to be mocked to always return a set value.
public function handleValue($value)
{
// Do a bunch of stuff...
$value += 20;
return $value;
}
}
My attempt at writing the tests.
class MyClassTest extends \PHPUnit_Framework_TestCase
{
public function testTheTestMethod()
{
// mock the object that is passed in as an arg
$arg = $this->getMockBuilder('SomeEntity')->getMock();
$arg->expects($this->any())
->method('getValue')
->will($this->returnValue(10));
// test handle document()
$myClass = new MyClass();
$result = $myClass->testMethod($arg);
// assert result is the correct
$this->assertEquals($result, 50);
}
}
I have tried mocking the MyClass object, but when I do that and call the testMethod it always returns null. I need a way to mock the one method but leave the rest of the object intact.
You can mock the class that you are testing and specify the method that you want to mock.
$mock = $this->getMockBuilder('MyClass')
->setMethods(array('handleValue'))
->getMock();
$mock->expects($this->once())
->method('handleValue')
->will($this->returnValue(23)) //Whatever value you want to return
However, IMO this is not the best idea for your tests. Testing like this will make refactoring much more difficult. You are specifying the implementation of the class rather than the behavior that the class is supposed to have. If handleValue is doing a lot of complicated work that makes testing difficult, consider moving the logic into a separate class and injecting that into your class. Then you can create a mock of that class and pass it in to testMethod. Doing so will give you the added advantage of making MyClass more extensible if handleValue needs to adapt its behavior.
http://www.oodesign.com/strategy-pattern.html
As a general rule, you should not mock the system that you are testing.
You can specify which methods to mock (partial mock) with setMethods():
// Let's do a `partial mock` of the object. By passing in an array of methods to `setMethods`
// we are telling PHPUnit to only mock the methods we specify, in this case `handleValue()`.
$csc = $this->getMockBuilder('Lightmaker\CloudSearchBundle\Controller\CloudSearchController')
->setConstructorArgs($constructor)
->setMethods(array('handleValue'))
->getMock();
// Tell the `handleValue` method to return 'bla'
$csc->expects($this->any())
->method('handleValue')
->with('bla');
Any other methods in the class not specified in the array you give setMethods() will be executed as is. If you do not use setMethods all methods will return NULL unless you specifically set them.

Is it possible, using PHPUnit mock objects, to expect a call to a magic __call() method?

I've got a mock object in a test. The real object, PageRepository, implements a magic method using __call(), so if you call $pageRepository->findOneByXXXX($value_of_field_XXXX), it will search the database for records matching that parameter.
Is there a way to mock that method?
The real method call would look something like this:
$homepage = $pageRepository->findOneBySlug('homepage');
The test would look like this:
$mockPageRepository->expects($this->any())
->method('findOneBySlug')
->will($this->returnValue(new Page()));
But it doesn't work -- PHPUnit doesn't spot the method call. The only way to get it to see the method is to define the method explicitly in PageRepository.
PHPUnit's getMock() takes a second argument, an array with the names of methods to be mocked.
If you include a method name in this array, the mock object will contain a method with that name, which expects() and friends will work on.
This applies even for methods that are not defined in the "real" class, so something like the following should do the trick:
$mockPageRepository = $this->getMock('PageRepository', array('findOneBySlug'));
Keep in mind that you'll have to explicitly include any other methods that also need to be mocked, since only the methods named in the array are defined for the mock object.
I found better way to do this. Still not perfect, but you don't have to specify all mocking class methods by hand, only magic methods:
$methods = get_class_methods(PageRepository::class);
$methods[] = 'findOneBySlug';
$pageRepositoryMock = $this->getMockBuilder(PageRepository::class)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->setMethods($methods)
->getMock();

Categories