Mocking find($collection) in repository pattern in Laravel with Mockery - php

I'm doing unit testing and my repository has this method:
/**
* #param int|Collection $id
* #return MyModel|Collection|null
*/
public function find($id);
I tried this:
$this->package_repo = Mockery::mock(PackageRepositoryInterface::class);
$this->app->instance('Package', $this->package_repo);
// ...
$this->ticket_repo->shouldReceive("find")->with(collect([]))->andReturn(/*...*/);
//...
echo $this->ticket_repo->find(collect([])); // Failed here.
The test immediately failed, and I think it's because the 2 collections in the shouldReceive expectation statement and the actual find statement are distinct objects.
If I want to mock the behavior of $this->ticket_repo->find($ids), what should I do?
Or rather, if there is a better way to design a testable algorithm, how would it be? Because I would like to have all the ids to I want to find be in an array, and be constructed into a single SQL select query, instead of a few hundred separate ones, for performance purposes.
Also asked here: https://laracasts.com/discuss/channels/testing/mocking-findcollection-in-repository-pattern-in-laravel-with-mockery#

You have to mock a concrete class and not the interface. Since you haven't provided the name I'm just guessing:
$mock = Mockery::mock(TicketRepo::class);
$this->app->swap('PackageRepo', $mock);
So now whenever someone asks for an instance by the Interface name they'll get the mock.

Related

PHP - Unit testing method with unmockable class in its body (PHPUnit)

I have a method that uses another class to calculate its outcome, that I want to test using PHPUnit.
/**
* Returns true if the given user has been granted the given permission.
*
* #param User $user
* #param AbstractPermission $permission
* #return bool
*/
public function userPermissionGranted(User $user, AbstractPermission $permission) : bool
{
// Retrieve model from database.
$user_permission = UserPermission::scopeUser($user)
->scopePermission($permission)
->first();
return $user_permission ? $user_permission->isGranted() : $permission->isGrantedByDefault();
}
Leaving out of consideration what this method actually does, I am wondering how to test this method. I can pass mocks of the User and AbstractPermission classes to the method, but the UserPermission class that is used inside the method's body (to retrieve a model from the database) I can do nothing with.
On top of that, if I pass mocks of the User and Permisson classes, they won't exist in the database, so when UserPermission queries the database, it will receive no results and the method will fail.
What do I do here? Is it considered good practice to simply mock the database (i.e. copying the live db structure and filling it with test data) and let my model query that database, and just trusting that everything is OK? Any suggestions on what to do here?
On a side note, UserPermission is an Eloquent model. I am merely making use of Eloquent here - without Laravel.
As a general rule, you can't directly mock static methods - at least, there's no good way to do it. Depending on how your application is set up, you might be able to hack something together that involves redefining the method with runkit or perhaps messing with includes/autoloader to load a mock class instead of the real one, but such solutions are kludgey at best.
One simple approach to allow unit-testing would be to wrap your static method calls in an instance method. So you'd create a new class with instance methods that call the static methods. Of course, you wouldn't be able to test that new class, but if it's a thin wrapper around the static methods then there's not really any value in testing it anyway.
So you might end up with something like this, for example:
class UserPermissionWrapper {
public function getUserPermission($user) {
return UserPermission::scopeUser($user);
}
}
Then you can inject that into your original class and get something like this:
public function userPermissionGranted(User $user, AbstractPermission $permission) : bool
{
// Assume this is an instance of UserPermissionWrapper injected at construction
$user_permission = $this->userPermissionWrapper
->getUserPermission($user)
->scopePermission($permission)
->first();
return $user_permission ? $user_permission->isGranted() : $permission->isGrantedByDefault();
}
Now you have an object calling instance methods, so you can inject a mock version of that class and set up the method calls in the normal way.
To answer my own question - and I've only come to a reasonable answer after a while of writing some more unit tests - I guess what it comes down to is this:
When testing the userPermissionGranted() method, we're actually only validating that the method works as expected. We're fetching a model from the database, and we may assume that this model has been tested already in its own, separate test. Given that we may assume that this model works as intended, and that we cannot access the database here to fetch the actual model, we can use a mock of the model, which we customly build to work just the way it should work, without actually performing any database work. That's where Peter Geer's answer comes in. Our class should contain a method to fetch the model from the database, so that instead of fetching and returning the model from the database, we can set up a mock and return that instead. In this case that means that in the return line of the method we're testing, we're going to test a mocked isGranted() on $user_permission (which is the mock we created to return a value that we want it to return), and isGrantedByDefault() on the $permission mock that we passed to the method when we called it.

Mocking callbacks in Laravel 4 (Mockery)

I'm currently writing tests for a package in Laravel 4.
I am mocking the Illuminate\Database\Query\Builder which works nearly all the time except when a where method uses a callback, I cannot check if the methods inside the callback are called.
I was hoping one of you could shed some light.
$query = \Mockery::mock('Illuminate\Database\Query\Builder', function ($mock) {
/** #var \Mockery\Mock $mock */
$mock->shouldReceive('where');
$mock->shouldReceive('orWhere')->twice();
});
And the actual where method that should call orWhere. Note: That builder mock gets passed to the class below.
$builder = new LaravelBuilder($query);
Which then calls $builder->filter() which contains the below code.
$this->query->where(function ($query) use ($filterData) {
/** #var \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $query */
foreach($filterData['columns'] as $colData) {
/** #var \Samvaughton\Ldt\Column $column */
$column = $colData['column'];
// See if this column is searchable
if (!$column->isSearchable() || !$colData['searchable']) continue;
// If the individual column term is empty, use the main term
$term = (empty($colData['term'])) ? $filterData['term'] : $colData['term'];
// Actually apply the filter
$query->orWhere($column->getSqlColumn(), "LIKE", "%{$term}%");
}
});
The main part is the bottom bit $query->orWhere, the PHPUnit tests fail every time as it doesn't run the orWhere even once. Before you say that it might not reach the execution of it due to continue, the data I am passing will allow this.
I suspect this is due to how I am mocking the where method in the first place. If I include an exit before the foreach it does not execute indicating that it doesn't even run anything inside the callback. I know that is the default behaviour but how do I get Mockery to run the same/similar callback?
I have tried using partial mocks, using shouldExpect but don't fully understand it. I've also tried searching around but no luck with this scenario.
Would be great if I could learn how to use mockery within callbacks.
OK so I think this can be done a better way, but I resorted to partially mocking Laravel's query builder.
See line 324 in Illuminate\Database\Query\Builder
When using a closure Laravel spawns a new query builder which also needs to be mocked. Here's the code that worked:
$query = \Mockery::mock('Illuminate\Database\Query\Builder', function ($mock) {
/** #var \Mockery\Mock $mock */
$mock->makePartial();
$mock->shouldReceive('where')->once()->passthru();
$mock->shouldReceive('newQuery')->andReturn(
\Mockery::mock('Illuminate\Database\Query\Builder', function ($mock) {
/** #var \Mockery\Mock $mock */
$mock->makePartial();
$mock->shouldReceive('orWhere')->twice();
})
);
});
I needed to use makePartial() so the query builder retained its original functionality for closures (which is not true to unit testing) so this isn't the best solution. From here I mock the newQuery method which is called to spawn a new query builder instance which I then mock in a similar format.

Testing a method which completely uses another objects methods

I am refactoring a class while writing unit tests for it.
There is a case that one of my methods is completely calling another object's methods which is injected to this class that I am testing.
So I have to mock the object that I have injected to class.
Now, the questing is that, does it worth to write unit tests for this particular method?
It seems to be strange to write unit tests which all it does it calling other object's methods which that object itself has to be mocked, then why am I testing this method at all?
Isn't the purpose of testing to check functionality of a method whether it works as expected or not?
If it is, then when I am mocking all it has and there is nothing left of that particular method to test then why should I test?
I am really confused!
The method which I'm stuck at is this (which is used for custom session handling):
public function write($sessionId, $sessionData)
{
$sth = $this->databaseConnection->prepare("INSERT INTO `{$this->DBTableName}` (`session_id`,`session_name`,`session_data`) VALUES(:session_id, :session_name, :session_data) ON DUPLICATE KEY UPDATE `session_data`=:session_data;");
$sth->bindValue(':session_id', $sessionId);
$sth->bindValue(':session_name', $this->sessionName);
$sth->bindValue(':session_data', $sessionData);
return $sth->execute();
}
here is link for this piece of code as well: http://pastebin.com/1FBeU6mb
By the way, I am newly started writing tests for my classes and I am beginner in this field of testing and inexperienced.
Thanks in advance.
I'm not really familiar with php, but it looks like you're just building and executing a database query, right?
Unless there's some other layer between this method and the database later that I don't see, there's really nothing here worth mock away. So you're right in the sense that mocking here does not give you a lot of value. And in one sense, testing this method is of limited value since you are really just testing the database layer, which generally we can assume is already correct and stable, and therefore does not need tests.
The value of mocking in general is that it allows you to simplify your tests by making assumptions about what other methods are doing, and allows you to not have to test those other methods indirectly.
In choosing to test the write method, what it turns out you are testing is that you have the correct steps in place to return the right results. That's it. I'm not familiar with php mocking frameworks, but I do know for frameworks in other languages you can set up what are called expectations, which lets you specify that a certain method will be called on a certain object with certain parameters. You can even often specify the order in which they should be executed. The takeaway here is that you are testing the outgoing messages your object is sending, and not the return values of those messages.
It is up to you to decide whether that is valuable vs. the maintenance this test will require.
You are testing if the right arguments are passed to your prepared statement. Besides you should test if the write method returns the prepared statment result.
If you do not test this there are several ways your application could break.
Renaming or removing of the methods arguments ($sessionId, $sessionData)
Renaming of your property $this->sessionName
Removing one of the bindValue calls.
Wrong naming of your bind aliases. They should match your query.
Returning something else than the result of execute().
etc. etc.
So yes it is good pratice to test this.
Assuming that your example describes a SessionHandler class, which looks similar to this:
class SessionHandler
{
public function __construct($sessionTableName, $sessionName, \PDO $databaseConnection)
{
$this->DBTableName = $sessionTableName;
$this->sessionName = $sessionName;
$this->databaseConnection = $databaseConnection;
}
// among others, your method write($sessionId, $sessionData) follows
}
this could cover the method write():
public function testWriteInsertsOrUpdatesSessionData()
{
/**
* initialize a few explaining variables which we can refer to
* later when arranging test doubles and eventually act
*/
$sessionTableName = 'sessions';
$sessionName = 'foobarbaz';
$sessionId = 'foo';
$sessionData = serialize([
'bar' => 'baz',
]);
$executed = true;
/**
* create a test double for the statement that we expect to be returned
* from `PDO::prepare()`
*/
$statement = $this->createMock(\PDOStatement::class);
/**
* set up expectations towards which methods should be invoked
* on the statement, specifying their order
*/
$statement
->expects($this->at(0))
->method('bindValue')
->with(
$this->identicalTo(':session_id'),
$this->identicalTo(sessionId)
);
$statement
->expects($this->at(1))
->method('bindValue')
->with(
$this->identicalTo(':session_name'),
$this->identicalTo($sessionName)
);
$statement
->expects($this->at(2))
->method('bindValue')
->with(
$this->identicalTo(':session_data'),
$this->identicalTo(sessionData)
);
$statement
->expects($this->at(3))
->method('execute')
->willReturn($executed);
/**
* create a test double for the database connection we inject
* into SessionHandler during construction
*/
$databaseConnection = $this->createMock(\PDO::class);
$databaseConnection
->expects($this->once())
->method('prepare')
->with($this->identicalTo(sprintf(
'INSERT INTO `%s` (`session_id`,`session_name`,`session_data`) VALUES(:session_id, :session_name, :session_data) ON DUPLICATE KEY UPDATE `session_data`=:session_data;',
$sessionTableName
)))
->willReturn($statement);
$sessionHandler = new SessionHandler(
$sessionTableName,
$sessionName,
$databaseConnection
);
$result = $sessionHandler->write(
$sessionId,
$sessionData
);
$this->assertSame($executed, $result);
}
For reference, see:
https://phpunit.de/manual/current/en/test-doubles.html

Is it a better practice to inject all variables in the constructor or to use setters and throw exceptions if they are not set?

Imagine you have this class
class Ai1ec_Less_Parser_Controller {
/**
* #var Ai1ec_Read_Variables_Startegy
*/
private $read_variable_strategy;
/**
* #var Ai1ec_Save_Variables_Strategy
*/
private $write_variable_strategy;
/**
* #var Ai1ec_Less_Variables_Collection
*/
private $less_variables_collection;
/**
* #var Ai1ec_Less_Parser
*/
private $ai1ec_less_parser;
/**
* We set the private variables in the constructor. I feel that there are too many parameters.
* Should i use setter instead and throw an exception if something is not set?
*
* #param Ai1ec_Read_Variables_Startegy $read_variable_strategy
* #param Ai1ec_Save_Variables_Strategy $write_variable_strategy
* #param Ai1ec_Less_Variables_Collection $less_variables_collection
* #param Ai1ec_Less_Parser $ai1ec_less_parser
*/
public function __construct( Ai1ec_Read_Variables_Startegy $read_variable_strategy,
Ai1ec_Save_Variables_Strategy $write_variable_strategy,
Ai1ec_Less_Variables_Collection $less_variables_collection,
Ai1ec_Less_Parser $ai1ec_less_parser ) {
}
}
I need those variables to be set and so i set them in the constructor ( but that look like too many parameters ). Another option would be to use setters to set them and then in a method throw an exception if one of the required variables is not set like this
public function do_something_with_parser_and_read_strategy() {
if( $this->are_paser_and_read_strategy_set === false ) {
throw new Exception( "You must set them!" );
}
}
private function are_paser_and_read_strategy_set () {
return isset( $this->read_variable_strategy ) && isset( $this->ai1ec_less_parser );
}
Do you think that one of the two methods is better?And why?
Is your class immutable? If so, then having 100% member population via the constructor is often the best way to do it, but I'll agree it can start to look ugly if you have more than a 5 or 6 parameters.
If your class is mutable then there's no benefit from having a constructor with required parameters. Expose the members via accessor/mutator methods (aka properties).
The factory pattern (as suggested by #Ray) can help, but only if you have a variety of similar classes - for a one-off then you can simply use static methods to instantiate the object, but you'll still have the "too many parameters" problem.
The final alternative is to accept an object with fields (one field for each parameter), but use this technique carefully - if some values are optional then just use method overloading (which unfortunately PHP doesn't support).
I'd just stick with what you're doing and only change it for something else if it presents a problem.
Class naming Controller somehow reflects MVC, or in general - any mechanism responsible for processing sequence.
Data object classes tend to have many fields in any case - it is their responsibility.
Regular object relying on many other objects could be possibly missing a point.
There are four objects, as I see: read, save, parse and provide collection interface to something.
Why shall one have different interfaces for reading and writing? Could this not be combined into one?
Parser shall be a library on itself, thus there may be no reason to combine it anywhere, although it could possible use readers/writers for itself, and, in return, provide collection. Thus could it be possible that parser would take an argument of reader and return a collection object?
That is more about specific case.
In general - having many arguments to the method (or initializing many fields within an object by other objects of different domains) indicates some sort of design flaw.
Kind of on-topic might be this article on Constructor Initialization - it advises to use in-constructor initialization. Just be sure to follow up to the point:
What if there's a lot of collaborators to provide in the constructor? A large list of construction parameters, like any large
parameter list, is a CodeSmell.
And as Ray has written - there is a possibility to initialize using setters, and there is article on that too. To the extent of my view - I think that Martin Fowler really summarizes these cases pretty well.
There is no "better" way. But here are few things you have to consider:
constructors are not inherited
if class requires too many objects, it is responsible for too much
This might have impact on your choice of what sort of interface your class implements.
The general rule of thumb would be this:
If parameters are mandatory for class to function, they should be injected through constructor.
The exception would be, if you initialize the instance by using a factory. It is quite common for factory to build instance form diverse classes, where some of them implement same interface and/or extend same parent class. Then it is easier to inject shared objects through setters.
Creating your objects using factories that call setters instead of using a constuctor of a set number of parameters is much more flexible. Check out the builder and factory patterns.
Throwing exceptions for accessing not fully built objects is good!
Any function that has over 2 (sometimes 3) arguments, I always pass an array, so it would look like:
public function __construct(array $options = array()) {
// Figure out which ones you truly need
if ((!isset($options['arg1'])) || (mb_strlen($options['arg1']) < 1)) {
throw new Exception(sprintf('Invalid $options[arg1]: %s', serialize($options)));
}
// Optional would look like
$this->member2 = (isset($options['arg1'])) && ((int) $options['arg2'] > 0)) ? $options['arg2'] : null;
// Localize required params (already validated above)
$this->member1 = $options['arg1'];
}
Passing an array of options allows for future growth without having to change the function signature. However it does have it's drawback in that the function must localize all elements of the array to ensure access doesn't throw warnings / errors (if an element is missing from the array).
The factory solution is in this case is not a good choice, because you are still left with the problem of passing the values to the factory so it can initialize the object with the correct values.
The standard solution to "too many constructor arguments" is the builder pattern. Your controller class itself will still have a long constructor, but clients can use setters on the builder, which in turn will later call the long constructor.
If you only construct your controller object in one or two places, it wouldn't even be worth all the trouble to create a builder; in that case, just stick with your current code.

Doctrine 2, query inside entities

How do I perform queries in an entity?
namespace Entities\Members;
/**
* #Entity(repositoryClass="\Entities\Member\MembersRepository")
* #Table(name="Members")
* #HasLifecycleCallbacks
*/
class Members extends \Entities\AbstractEntity
{
/**
* #Id #Column(name="id", type="bigint",length=15)
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Column(name="userid", type="bigint", length=26, nullable=true)
*/
protected $userid;
/**
* #Column(name="fname", type="string", length=255,nullable=true)
*/
protected $fname;
/**
* #OneToMany(targetEntity="\Entities\Users\Wall", mappedBy="entry", cascade={"persist"})
*/
protected $commententries;
public function __construct()
{
$this->commententries = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Example I would like to have a function inside this entity called: filter()
and I want to be able to filter the commententries collection. It should return a collection with a certain condition such id=1. Basically it should be filtering the data received from the join query.
So something like this:
$this->commententries->findBy(array('id' => 1));
But obviously this does not work.
Your ArrayCollection already implements a filter() method, you need to pass a Closure to get it to work your entities (here, the commentEntries).
$idsToFilter = array(1,2,3,4);
$member->getComments()->filter(
function($entry) use ($idsToFilter) {
if (in_array($entry->getId(), $idsToFilter)) {
return true;
}
return false;
}
);
(not tested)
Note that such method will iterate and eager load over all your Comments, so in case where a User has a lot it may be a big bottleneck;
In most case, you want to use a custom repositories, where you can place such logic.
As timdev suggested, you can create a MemberService which will wrap such call by being aware of the EntityManager.
Separating Entities from the Peristance Layer is a big improvement over Doctrine 1, and you should not break that rule.
Generally speaking, you shouldn't do this.
Entities, as a rule of thumb, should not know about the entitymanager (directly, or via some intermediary object).
The reason for this is mostly testability, but in my experience, it helps keeps things organized in other ways.
I'd approach it by designing a service class that handles the lookups for you. Your controller (or whatever) would drive it like this:
<?php
// create a new service, injecting the entitymanager. if you later wanted
// to start caching some things, you might inject a cache driver as well.
$member = $em->find('Member',$member_id); //get a member, some how.
$svc = new MemberService($em);
$favoriteCommentaries = $svc->getFavoriteCommentaries($member);
As I hint in the comment, if you decide later that you want to add caching (via memcached, for instance) to avoid frequent lookups, you'd do that somewhere near or in this service class. This keeps your entities nice and simple, and easily testable. Since you inject your entitymanager into the service at construction-time, you can mock that as needed.
getFavoriteCommentaries() could use various implementations. A trivial one would be to proxy it to Member::getFavoriteCommentaries(), which would actually load everything, and then filter out the "favorite" ones. That probably won't scale particularly well, so you could improve it by using the EM to fetch just the data you need.
Use a custom repository for queries
You should not write queries in your entities, but you should use a repository for that. This is also explained in the doctrine documentation 7.8.8 Custom Repositories. It will allows you to build your custom queries on a central spot and keeps your entity definitions clean.
Use criteria to filter collections:
But if you want to filter inside your collection in a get method you can use Criteria. You can read on how to use Criteria in the Doctrine documentation 8.8 Filtering collections. To filter like you want to do would look something like this:
Declare at the top of your entity class the Criteria class
use Doctrine\Common\Collections\Criteria
In your getCommentEntries method use the class to filter:
public function getCommentEntries()
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('id', 1));
$filteredCommentEntries = $this->commententries->matching($criteria);
return $filteredCommentEntries;
}
Your question was really hard to understand, please try and work on how you structure your questions in the future. For instance, you say "return back the same result" but "filter", which could mean anything. Do you want to use the same result set (why on earth would you ever choose to do that), and just use array_filter or array_walk to filter the results or do you actually want to use a conditional join? It's incredibly ambiguous.
Anyway.. answer ( after reading your question 4 times).
$q = $qb->select ( "m","w" )
->from ( "Members", "m" )
->leftJoin( "m.commententries","w",'WITH', 'w.id = :id')
->setParameter ( "id", $id )
->getQuery ();
I agree with "timdev". You shouldn't define query in your entities class. My way to define a service class support the entities are repository classes. For example: User (entity -- YourBundle/Entity/User.php) will have UserRepository (service class -- YourBundle/Repository/UserRepository.php). Your "filter" method should be in here. You just need to map this service class in your entity class. In your controller, you can always access the "filter" via its repository. It's documented very detail in the Symfony2 book

Categories