Testing objects with dependencies in PHPUnit - php

For objects which compose another object as part of their implementation, what's the best way to write the unit test so only the principle object gets tested? Trivial example:
class myObj {
public function doSomethingWhichIsLogged()
{
// ...
$logger = new logger('/tmp/log.txt');
$logger->info('some message');
// ...
}
}
I know that the object could be designed so that the logger object dependency could be injected and hence mocked in a unit test, but that's not always the case - in more complicated scenarios, you do need to compose other objects or make calls to static methods.
As we don't want to test the logger object, only the myObj, how do we proceed? Do we create a stubbed "double" with the test script? Something like:
class logger
{
public function __construct($filepath) {}
public function info($message) {}
}
class TestMyObj extends PHPUnit_Framework_TestCase
{
// ...
}
This seems feasible for small objects but would be a pain for more complicated APIs where the SUT depended on the return values. Also, what if you want to test the calls to the dependency object in the same was you can with mock objects? Is there a way of mocking objects which are instantiated by the SUT rather than being passed in?
I've read the man page on mocks but it doesn't seem to cover this situation where the dependency is composed rather than aggregated. How do you do it?

Following troelskn advise here's a basic example of what you should do.
<?php
class MyObj
{
/**
* #var LoggerInterface
*/
protected $_logger;
public function doSomethingWhichIsLogged()
{
// ...
$this->getLogger()->info('some message');
// ...
}
public function setLogger(LoggerInterface $logger)
{
$this->_logger = $logger;
}
public function getLogger()
{
return $this->_logger;
}
}
class MyObjText extends PHPUnit_Framework_TestCase
{
/**
* #var MyObj
*/
protected $_myObj;
public function setUp()
{
$this->_myObj = new MyObj;
}
public function testDoSomethingWhichIsLogged()
{
$mockedMethods = array('info');
$mock = $this->getMock('LoggerInterface', $mockedMethods);
$mock->expects($this->any())
->method('info')
->will($this->returnValue(null));
$this->_myObj->setLogger($mock);
// do your testing
}
}
More information about mock objects can be found in the manual.

As you seem to be aware already, Concrete Class Dependencies makes testing hard (or outright impossible). You need to decouple that dependency. A simple change, that doesn't break the existing API, is to default to the current behaviour, but provide a hook to override it. There are a number of ways that this could be implemented.
Some languages have tools that can inject mock classes into code, but I don't know of anything like this for PHP. In most cases, you would probably be better off refactoring your code anyway.

Looks like I misunderstood the question, let me try again:
You should use the singleton pattern or a factory for the logger, if it's not too late already:
class LoggerStub extends Logger {
public function info() {}
}
Logger::setInstance(new LoggerStub());
...
$logger = Logger::getInstance();
If you can't change the code, you could use a catch-all class that is overloading __call()
class GenericStub {
public function __call($functionName, $arguments) {}
}

There is actually a reasonably new extension for PHP class overloading released by the same guys that build PHPUnit. It lets you override the new operator in cases where you can't refactor the code, unfortunately it isn't that simple to install on Windows.
The URL is http://github.com/johannes/php-test-helpers/blob/master/

Related

Laravel - How can I mock/stub a method on a model correctly

How can I mock/stub a method on a model correctly (in laravel)? Currently I am trying...
$mock = Mockery::spy(Organisation::class);
$mock->shouldReceive('findByCustomerId')->once();
and the code under test is
use App\Organisation;
...
public function handle()
{
$org = Organisation::findByCustomerId(1234);
However when I run the tests I get an error Call to undefined method App\Organisation::findByCustomerId(), which tells me that the class/model is not being mocked correctly, does anyone know where I could be going wrong?
Mockery doesn't automatically overload classes when you create a mock for them (like some other libraries might do). It does support overloading, but I couldn't figure out how to overload a class with a partial mock.
So it looks like you'll have to use dependency injection to "inject" the mock object into the class that is being tested:
class TestedClass
{
private $organisation;
public function __construct(Organisation $organisation)
{
$this->organisation = $organisation;
}
public function handle()
{
$org = $this->organisation->findByCustomerId(1234);
}
}
Laravel with automatically inject the correct object for you. To inject your mock object instead of the Organization class you can do something like this in your test:
$mock = \Mockery::spy(Organization::class)->makePartial();
$mock->shouldReceive('findByCustomerId')->once();
$this->app->instance(Organization::class, $mock);

How do i create a mock object that uses an array of traits?

I am currently on PHPUnit v5.7.27
I would like to create a mock object that uses an array of traits. How would I go about this? I only see getMockForTrait as a way to create a mock object using a single trait. My issue is that the trait requires the existence of another trait at the class level.
Update: More context to the issue
Given:
trait GetSet {
public function __call(){ /* does some magic */
}
trait RepositoryAware {
public function getRepository(string $name)
{
/* makes use of the GetSetTrait*/
}
}
class Controller
{
use GetSet;
use RepositoryAware;
}
Given the limitations of PHP, I can not simply put a use GetSet on the RepositoryAware trait because other traits that the controller imports could also bring the GetSet trait. Furhtermore, the controller class itself could be using the behavior provided by the GetSet trait.
The current solution I have is to create a Dummy Class that imports both traits and mock that class instead:
class RepositoryAwareClass
{
use GetSet;
use RepositoryAware;
}
Like this I am able to properly test the behavior provided by the RepositoryAware trait while at the same time composing its requirement of the GetSet trait.
Mocking concept was built with the idea that you would be using dependency injection. I can certainly see why you may not want to use dependency injection with this multiple inheritance like model that php uses called "Traits". Mocking tools like the one built for phpunit was built to substitute instances of objects not classes/interfaces/traits themselves. PHP Traits are more like having a static dependency instead of a dependency on an instance of an object. However, even if you were using traits and assuming a trait was basically the same as a class, according to mocking best practices should test the trait as its own test instead of testing a trait through another class. If you want to mock the trait itself you may want to try to revisit your design as I do not believe it can be done. You can certainly mock a trait and test that trait but you cannot mock a trait and then inject it as a dependency on an object. Imagine that a class for example implements an interface, mocking a trait would be the same a mocking an interface that a class implements, its not possible. You can only mock an interface of an object that a class depends upon through setter or constructor based dependency injection. Another example would be to try and mock the class that the class under test inherits from. You can't do that either. Perhaps in the javascript world this type of thing could be useful and from some people's point of view desired, but I think if you want to use mocking you would need to stick with object dependency injection instead of static use of traits.
So what's the alternative? I think the following example would be how to use perhaps "traditional" OOP practices with mocking to achieve your goal of sharing functionality without using inheritance. The example also makes your dependencies more explicit. And for the record, I applaud you for NOT using inheritance.
<?php
interface GetterSetter {
public function __call();
}
interface RepositoryProvider {
public function getRepository(string $name);
}
class GetSet implements GetterSetter {
public function __call() {
/* does some magic */
}
}
class DefaultRepository implements RepositoryProvider, GetterSetter {
/**
* #var GetterSetter
*/
private $_getterSetter;
public function __construct(GetterSetter $getterSetter) {
$this->_getterSetter = $getterSetter;
}
public function getRepository(string $name) {
// makes use of the GetSetTrait
$this->__call();
}
public function __call() {
// makes use of the GetSetTrait
$this->_getterSetter->__call();
}
}
class Controller implements RepositoryProvider, GetterSetter {
/**
* #var RepositoryProvider
*/
private $repositoryProvider;
public function __construct() {
$this->repositoryProvider = new DefaultRepository(new GetSet());
}
public function getRepository(string $name) {
return $this->repositoryProvider->getRepository($name);
}
public function __call() {
$this->repositoryProvider->__call();
}
}
In general I feel like the PHP community took a wild left turn, trying to be more like javascript and I feel that traits can walk you into a corner. This is a very good example of such a corner. I would really avoid them, at least for now. In the long run I believe Generics would be the better solution to your problem of needing a generic GetSet piece of code but generics haven't been implemented in php yet :-(.

PHPUnit mock faster and don't repeat the code

I like to ask you about your practice of writing unit test, how to mock object and don't repeat the code?
I am using Symfony2 framework and for example I have many bundles with custom validators. When me and the rest of my team writing unit test we repeat the code of mocking Constraint, ExecutionContext, ConstraintViolationBuilderInterface. I know that we can create trait or abstract class or something else where we can store code responsible for mocking but before I will start doing this I like to know your best practices.
My first idea was to create a class/trait which will store for example mock of all repositories. Example:
class MockRepositoryHelper extends \PHPUnit_Framework_TestCase
{
public function getUserRepositoryMock()
{
return $this->prophesize(UserRepository::class);
}
// next repositories getters
}
and then use this code in real test case:
class EmailValidator extends \PHPUnit_Framework_TestCase
{
private $mockRepositoryHelper;
public function setUp()
{
parent::setUp();
$this->mockRepositoryHelper = new MockRepositoryHelper();
}
/**
* #test
*/
public function it_should_find_user()
{
$userRepository = $this->mockRepositoryHelper->getUserReposioryMock();
$userRepository->findUser(Argument::type('string'))->willReturn(null);
// rest of the test
}
}
Of course this is only pseudo code what I imagined, my first thought. What are yours ideas?
Basically I am asking how to write unit test faster and don't repeat the code?

ZF2, class implementing FactoryInterface pass ServiceLocator instance as attribute

I have a factory that implements FactoryInterface, like:
class SomeFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
// the code to create SomeClass instance
}
}
Now, all the code is inside the createService method (multiple ifs, some queries, etc.) which makes the method long and difficult to follow. I'd like to refactor the code by extracting the some pieces of code into separate methods. Problem is for my case, I end up passing the instance of $serviceLocator->getServiceLocator() in each of these methods, which is no problem really, but feels ugly.
I was wondering if there's an elegant way of maybe assigning the attribute of SomeFactory $serviceLocator->getServiceLocator() than just passing it in every extracted method.
I think you don't really understand Factories usage.
A factory is ONLY used to inject dependencies in another object, like a Controller or a Service.
So, sure, it depends of what you want to do, but I think you want to create a Service to do some think.
Example :
class MyService implements ServiceLocatorAwareInterface
{
use ServiceLocatorAwareTrait; // used to inject SL getter and setter in your code
public function myMethod1()
{
$formElementManager = $this->getServiceLocator()->get('formElementManager');
// ... etc ...
}
public function myMethod9999() ......
}
class MyServiceFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$myService = new MyService();
$myService->setServiceLocator($serviceLocator);
$myService->setAnotherProperty(...);
return $myService;
}
}
If ServiceLocator is really needed in your MyService() class, it's recommended to inject it in the __construct() method

PHPUnit best practice for fixation of value returned by protected method?

consider the following code as PHP-style pseudo code to get my point across.
class C extends PHPUnit_Framework_TestCase
{
public function m1()
{
$v = $this->m2();
if($v == "x")
{
throw new Exception();
}
}
protected function m2()
{
[...];
return $v;
}
}
now I want to add a test that asserts that an Exception is thrown if m2() returns "x".
How can I simulate that?
I thought about using Reflection to redefine the method during runtime, but it seems that Reflection doesn't offer such a functionality and I would have to resort to experimental extensions like classkit or runkit. Would that be the way to go?
In this case I could extend the class and redefine m2() but where would I put that derived class then? In the same file as the test?
The latter solution wouldn't work anymore if I would choose m2 to be private.
I'm quite sure that there is a best practice to deal with this situation.
Ether I'm completely off on what you are trying to do here or you are doing something that confuses me greatly.
To me is seems that you are asking for is that you want to check that your test method throws an exception.
class C extends PHPUnit_Framework_TestCase
Why would you want to test your test method?
I'm going to assume that that is the real class and not your test
In that case I always strongly argue for just testing it as if the protected method would be inline in the public method.
You want to test the external behavior of your class. Not the implementation. The protected method is and implementation detail that your test shouldn't care about. That would mean that you would have to change your test when you change that protected method.
And from there on out:
class CTest extends PHPUnit_Framework_TestCase {
public function testM1NormalBehavior() {
}
/**
* #expectedException YourException
*/
public function testM1ThrowsExceptionWhenM2ConditionsAreMet() {
$c = new C('set_Up_In_A_Way_That_Makes_M2_Return_X');
$c->m1();
}
}
You can use a partial mock of C to force m2() to return "x". I'll assume that the extends PHPUnit_Framework_TestCase was accidental and that C is actually the class under test and not the unit test itself.
class CTest extends PHPUnit_Framework_TestCase {
/**
* #expectedException Exception
*/
function testM1ThrowsExceptionWhenM2ReturnsX() {
$c = $this->getMock('C', array('m2'));
$c->expects($this->once())->method('m2')->will($this->returnValue('x'));
$c->m1();
}
}

Categories