I know what dependency injection is and why to use it (it's better to inject class than to use new keyword because it's kind of makes impossible to test it later). I'm going to talk about Laravel's ways of how to write controllers.
Way 1)
Let's say I have the following function in controller and I want to test it.
public function index() {
$allActors = \App\Actor::all();
foreach($allActors as $actor){
$actor->name="gio";
}
return $allActors;
}
As you see, controller and model is tightly coupled. My question is why I can't test this method? I looked through Laravel's mockery and I think it could be tested. What I'd do is before making a call to index method, I'd mock the \App\Actor and what it should return. Why shouldn't I follow this idea?
Way 2)
protected $actor;
public function __construct(\App\Actor $actor){
$this->actor = $actor;
}
public function index() {
$allActors = $this->actor->all();
foreach($allActors as $actor){
$actor->name="gio";
}
return $allActors;
}
Now you think this could be tested? how? One thing I can think of is before creating new controller, I'd create new class that extends Actor model and override its functions, in this case all() function and get the results from file.
The main question is why can't I test it in the first example and in the second example? Which one is better for DI? It seems like the second option is DI, but I looked through Laravel's docs and I think the first example can be mocked still. But I also read that Eloquent models can't be mocked. I am seeking a whole idea about all of this.
Related
I'm new to testing and writing testable code, and am looking for some clarification on the correct way to handle this simple scenario. I've read other questions and answers on SO with similar titles but they do not seem to offer a clear answer to what I'm asking.
I have a controller that calls the shipped() method on an instance of my Picking class:
class MyController extends \BaseController {
public function controllerMethod() {
$picking = new Picking;
$picking->shipped($shipmentData);
}
}
The Picking model looks like this:
class Picking extends \Eloquent {
public function order() {
return $this->belongsTo('Order');
}
public function shipped($shipmentData) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$this->order->pickingShipped();
}
}
As you can see, this shipped() method saves some data, and then calls the pickingShipped() method, on it's related Order.
Now, I am trying to write a test for the shipped() method, and I'm not sure the appropriate way to do this. I've read about mocking, but I am confused if this is a situation where mocking is necessary. I've thought of a few possible solutions, but I'm not sure if any of them are correct.
1) Rearrange the code so that the controller calls the pickingShipped() method allowing it to be removed from the shipped() method, simplifying the test.
For example, the last line of the shipped() method would be removed, and the controller code would change to:
$picking = new Picking;
$picking->shipped($shipmentData);
$picking->order->pickingShipped();
2) In the test, use a mock method on order so that the test can simply confirm that the pickingShipped() method gets called.
Something along the lines of what's explained here. That would mean the test could do something like this:
$order->expects($this->once())->method('pickingShipped')
However, I think that would mean that I also need to inject the order dependency rather than relying on the order relationship within the shipped() method, like this:
class Picking extends \Eloquent {
public function order() {
return $this->belongsTo('Order');
}
public function shipped(Order $order, $shipmentData) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$order->pickingShipped();
}
}
And then the code in the controller would have to look like this:
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
This feels a little strange, but I'm really not sure what's right.
My question is, what is the proper way to write and test this code? It's easy to test the the shipped() method sets the appropriate data on itself, but what about that call to pickingShipped() at the end? This seems to make the testing more complicated. So should the code be rearranged? If so, how? Or, is this a common use-case for mocking like I outlined in the 2nd option? If so, is it correct to inject the dependency as I'm showing?
I'm not a PHP dev so this might come down to language features being a blocker.
I would suggest that the dependency injection method is better because it calls out the dependency and would allow you to separate your persistence and behavior later. For instance the Picking or Picker might be a better behavior name whilst PickingRecord might be nice for the data.
In any case if you can set default arguments in PHP then I like the last method you used (injection) and you could currently simplify to something like
public function shipped($shipmentData, Order $order = $this->order) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$order->pickingShipped();
}
This then would allow you to ignore the order dependency in production code and inject a double or other type of object as an order in tests and simply assert that the method was called on the order object. Integration tests should continue to monitor that the interfaces still mesh together even though you're injecting doubles in your unit tests.
This would be how I'd attempt to do this in Ruby.
I came up with a solution that I feel good about. It seems pretty obvious now that I see it. All I did was set the $picking->order property to return the mocked order for the test.
$order = Mockery::mock(Order::class);
$picking = new Picking;
$picking->order = $order;
$order->shouldReceive('pickingShipped')
->with($picking)
->once();
$picking->shipped($shipmentData);
Now when the shipped() method calls $this->order, it gets the mocked $order object I defined, and the test works correctly.
This feels like the right solution.
<?php
use yii\db\ActiveRecord;
class Model extends ActiveRecord
{
protected static $ids = [];
public static function getIds()
{
if (empty(static::$ids)) {
static::$ids = static::find()->select('id')->column();
}
return static::$ids;
}
}
How to use the test to make sure that the query is executed once by repeatedly calling this method ?
Preferably using codeception or phpunit.
Tests are not just a way to ensure your code works, they also help identify code smells. In your case writing a test is hard, because you use static methods.
There used to be a staticExpects method but that was deprecated in phpunit long ago, so that's not really feasible. The best way to make this code testable is to remove the static keyword. This is easy for getIds() but since the static find() is defined by a 3rd party (yii's ActiveRecord) you can't really remove it. Instead you could wrap it in a non-static method. This gives you the benefit of being able to move away from the Active Record to some other implementation like Doctrine in the future, by just touching these small methods wrapping the 3rd party code.
Once you do this you could create a partial mock of your model to make sure that method is called:
class Model extends ActiveRecord
{
private $ids;
protected function findIds()
{
return static::find()->select('id')->column();
}
public function getIds()
{
if (empty($this->ids)) {
$this->ids = $this->findIds()
}
return $this->ids;
}
}
and in your test:
public function testFindIdsIsCalledWhenGetterIsNotInitialized()
{
$model = $this->getMockBuilder(Model::class)
->setMethods(['findIds'])
->getMock();
$model->expects($this->once())
->method('findIds')
->will($this->returnValue([1, 2, 3]));
$ids = $model->getIds();
$this->assertEquals([1, 2, 3], $ids);
}
This should have 2 assertions, one for the expected method call and one for the returned values. This test bypasses the Active Record and only ensures that your getIds() method works as expected. Another way to approach this is, as mentioned in the comments to your question, to use a functional test that actually tests the database interactions by fetching the data from a (test) database. Obviously since this requires having a database connection and retrieving test data, e.g. from some previously setup fixtures, it's a bit more work and the test will be slower. Depending on how big your project is that might not be an issue and you might feel more comfortable testing the logic in the Active Record implementation as well.
Over the past two years, I have become fairly familiar with PHP MVC style architecture, and have developed all my projects using MVC structures since then.
One question that has continued to bother me is how to group functions and database calls. I run into needing to perform the same actions across models. I would prefer not to duplicate these operations and sql query inside each of the models, but would rather group all user operations into a separate class.
For example, say I have a website with a forum, a blog, and a profile page, each with a separate model, view, and controller. However, say each of these pages needs to perform the same operation to the user table.
My Model class is constructed with a database object automatically. If I need to call a function from the user class, is it ok to pass the db object to that new User class? ... to do something like the following? I am not sure if passing objects like I am doing is fine, or is there a much better way of setting things up? Am I wasting resources, or is this a clumsy way of doing things?
Profile Model
class Profile_Model extends Model{
public function __construct() {
parent::__construct();
}
public function someFunction(){
$this->db->insert( "SOME SQL" );
$user = new User( $this->db ); // OK TO PASS DB OBJECT LIKE THIS?
$user->setSomething();
}
public function anotherFunction(){
//do something else that does not need a user object
}
}
User Class
class User{
public function __construct($db){
$this->db = $db; // OK TO SET DB OBJECT AS CLASS VARIABLE AGAIN?
}
public function setSomething(){
$this->db->insert( "SOME SQL" );
}
}
I'm trying to give you a really basic example of how I'd implement this architecture; Since it's really basic and I'm just a passionate developer and nothing more it could be I'm breaking some architectural rules, so please take it as a proof of concept.
LET'S START quickly with the Controller part where you get some request. Now you need someone that takes care of doing the dirty work.
As you can see here I'm trying to pass all the "dependencies" via constructor. These way you should be able to easily replace it with Mocks when testing .
Dependency injection is one of the concepts here.
AND NOW the Model (please remember Model is a layer and not a single class)
I've used "Services (or cases)" that should help you to compose a group of behaviors with all the actors (Classes) involved in this behavior.
Idendifying common behaviours that Services (or Cases) should do, is one of the concepts here.
Keep in mind that you should have a big picture in mind (or somewhere else depending on the project) before starting, in order to respect principle like KISS, SOLID, DRY, etc..
And please pay attention to method naming, often a bad or long name (like mine for example) is a sign that the class has more than a single Responsability or there's smell of bad design.
//App/Controllers/BlogController.php
namespace App\Controllers;
use App\Services\AuthServiceInterface;
use App\Services\BlogService;
use App\Http\Request;
use App\Http\Response;
class BlogController
{
protected $blogService;
public function __construct(AuthServiceInterface $authService, BlogService $blogService, Request $request)
{
$this->authService = $authService;
$this->blogService = $blogService;
$this->request = $request;
}
public function indexAction()
{
$data = array();
if ($this->authService->isAuthenticatedUser($this->request->getSomethingRelatedToTheUser())) {
$someData = $this->blogService->getSomeData();
$someOtherData = $this->request->iDontKnowWhatToDo();
$data = compact('someData', 'someOtherData');
}
return new Response($this->template, array('data' => $data), $status);
}
}
Now we need to create this Service that we've used in the controller. As you can see we're not talking directly with the "storage or data layer" but instead we're calling an abstraction layer that will handle that for us.
Using a Repository Pattern to retrieve data from a data layer, is one of the concepts here.
this way we can switch to whatever repository (inMemory, other storage, etc) to retrieve our data without changing the interface that the Controller is using, same method call but get data from another place.
Design by interfaces and not by concrete classes is one of the concepts here.
//App/Services/BlogService.php
<?php
namespace App\Services;
use App\Model\Repositories\BlogRepository;
class BlogService
{
protected $blogRepository;
public function __construct(BlogRepositoryInterface $blogRepository)
{
$this->blogRepository = $blogRepository;
}
public function getSomeData()
{
// do something complex with your data, here's just simple ex
return $this->blogRepository->findOne();
}
}
At this point we define the Repository that contains the persistance handler and knows about our Entity.
Again decoupling storage Persister and knowledge of an entity (what "can" be coupled with a mysql table for example), is one of the concepts here.
//App/Model/Repositories/BlogRepository.php
<?php
namespace App\Models\Respositories;
use App\Models\Entities\BlogEntity;
use App\Models\Persistance\DbStorageInterface;
class DbBlogRepository extends EntityRepository implements BlogRepositoryInterface
{
protected $entity;
public function __construct(DbStorageInterface $dbStorage)
{
$this->dbStorage = $dbStorage;
$this->entity = new BlogEntity;
}
public function findOne()
{
$data = $this->dbStorage->select('*')->from($this->getEntityName());
// This should be part of a mapping logic outside of here
$this->entity->setPropA($data['some']);
return $this->entity;
}
public function getEntityName()
{
return str_replace('Entity', '', get_class($this->entity));
}
}
At the end a simple entity with Setters and Getters:
//App/Model/Entities/BlogEntity.php
<?php
namespace App\Models\Entities;
class BlogEntity
{
protected $propA;
public function setPropA($dataA)
{
$this->propA = $dataA;
}
public function getPropA()
{
return $this->propA;
}
}
AND NOW? how can you inject this classes passed as dependencies? Well, this is a long answer.
Indicatively you could use Dependency Injection as we've done here have a init/boot file where you define things like:
// Laravel Style
App::bind('BlogRepositoryInterface', 'App\Model\Repositories\DbBlogRepository');
App::bind('DbStorageInterface', 'App\Model\Persistence\PDOStorage');
or some config/service.yml file like:
// Not the same but close to Symfony Style
BlogService:
class: "Namespace\\ConcreteBlogServiceClass"
Or you may feel the need of a Container Class from where you can ask the service you need to use in your controller.
function indexAction ()
{
$blogService = $this->container->getService('BlogService');
....
Dulcis in fundo here are some useful links (You can find tons of docs about this):
Services in Domain-Driven Design
Wicked Domain Model
Dependency Injection Container
Inversion of Control and Dependency Injection
Managing common Dependencies with parent Services
Whenever you need to use an object from another class there is only one safe way to do it: Dependency Injection.
Example:
Instead of having:
public function myMethod(){
$anotherObject = new Object();
}
You should inject the object with the constructor:
function __construct($dependency) {
$this->anotherObject = $dependency;
}
Once you have this structure you can use type hint and an Inversion of Control container to build thing automatically, e.g. define:
function __construct(DependencyInterface $dependency) {
$this->anotherObject = $dependency;
}
And then set your IoC container to inject the right dependency when you need to use this object
Do you use any frameworks? If not, try having a look at some popular ones, like Zend Framework or Symfony. You'll find they solve your problem and probably many more and are a great way to expand your knowledge on how to structure your project.
That aside you are close. Although adding the database directly to your User-model is probably not want you want to do. If you can get Martin Fowler's Patterns of Enterprise Application Architecture (PEAA) you will find a whole chapter outlining how to connect your models to your database. I prefer a Gateway-class (search for the Gateway-pattern or look at Zend_Db) when building something on my own, as it is relatively easy to implement and build.
Basically you have a class which performs queries and then will pass the data to your model. Just look at Data Source Architectural Patterns in Martin Fowler's pattern catalog (http://martinfowler.com/eaaCatalog/) to get a quick glance how to structure it and definitely read the book to get a real understanding when and how to use the patterns.
I hope this helps.
Part of the answer is to use dependency injection, but there is more to it than that. Cognitively speaking, grouping starts in the mind and is teased out better by brainstorming and modeling: Entity Relationship Diagrams and UML Diagrams.
Grouping of methods into classes and delegating tasks to injected objects makes sense, but there is usually room for one level of inheritance (at minimum). The use of abstract super classes and a Strategy Pattern for child classes that inherit base functionality from the abstract parent can help reduce code duplication (DRY).
All that being said, this is one reason why dependency injection containers are popular. They allow you to obtain the objects, and hence functionality, you need anywhere, without coupling object instantiation to usage.
Do a search for Pimple in Google. It may give you some ideas.
I am having some trouble applying Factory Pattern.
I have a class that I usually call as Product($modelNumber, $wheelCount). But in a part of legacy code that I am refactoring, I do not have $modelNumber, and only have $productID, where the link between {$modelNumber, $productID} is in the database (or in my case I can hardcode it, as I only have a select few products at the moment).
I need to be able to create my class using $productId, but how?
Using Procedural ways I would have a function that does the lookup, and I would put that function in a file, and include that file anywhere where I need to do the lookup. Thus do this:
$modelNumber = modelLookup($productId)
Product($modelNumber, $wheelCount);
But how do I do it using Object Oriented way?
Note: I have posted a more detailed situation here: https://softwareengineering.stackexchange.com/q/233518/119333 and this is where Factory pattern (and other patterns, like interfaces and function pointer passing) were suggested conceptually, but I hit a wall when trying to implement them in PHP. It kind of seems like a simple question, but I think there are several ways to do it and I am a bit lost as to how. And so I need some help.
I provided a conceptual answer to your SRP problem on Programmers Exchange but I think I can demonstrate it here.
What you basically want is some other object that will do the work to get you the model number of given product ID.
class ProductModelNumberProvider {
public function findByProductId($productId) {
// The lookup logic...
}
}
Your factory should provide a setter constructor so it can make use of this object internally to lookup the model number if needed. So basically you will end up with a ProductFactory similar to this.
class ProductFactory {
private $productModelNumberProvider;
public function __construct(ProductModelNumberProvider $productModelNumberProvider) {
$this->productModelNumberProvider = $productModelNumberProvider;
}
public function getProductByIdAndWheels($productId, $wheels) {
$modelNumber = $this->productModelNumberProvider($productId);
return $this->getProductByModelNumberAndWheels($modelNumber, $wheels);
}
public function getProductByModelNumberAndWheels($modelNumber, $wheels) {
// Do your magic here...
return $product;
}
}
EDIT
On second thought the setter is not the best approach since having a ProductModelNumberProvider instance is mandatory. That is why I moved it to have it injected through the constructor instead.
I can think of something like this:
$factory = new ProductBuilder();
$factory->buildFromProductId($productId, $wheelCount); //uses modelLookup() internally
$factory->buildFromModelNumber($modelNumber, $wheelCount); //just returns Product()
It is basically creating a class on top of the procedural function, but it does separate the logic of creating the class separately from looking up the mapping.
I'm writing a fairly simple "fact database" in PHP (with Codeigniter .. but I am trying to get away from the framework internals for learning purposes), and trying to better my MVC/OOP practices.
Previously I would have done this: a fact model, a user model, a source model .. and inside each of those models I would place the CRUD logic for each. So it would look like this..
$this->fact_model->save($fact);
$this->user_model->deactivate($uid);
$this->source_model->get_id($sid);
But after reading more, it seems to make sense to have a separate persistence model (ie 'database_model'). But then it seems it would have to contain a full range of CRUD for each type of object, which seems wasteful to me. I guess I'm looking for how to go to this...
$this->db_m->save(Fact $fact);
$this->db_m->update(User $user);
// .. etc .. but also ..
$this->db_m->get_user_id($uid);
// .. and ..
$htis->db_m->get_all_facts();
Is this heading in the right direction? Do I just end up testing for type inside the database model and switching when I need to? Or do I extend the database model for each type of object?
$this->fact_db_m->save(Fact $fact);
$this->fact_db_m->get_all();
$this->source_db_m->get_id($sid);
Or something like this, which I guess is the closest to CIs AR implementation.
$this->db_m->save('facts', Fact $fact);
$this->db_m->get('user', array('id'=>$uid));
I guess this is a case of "active record vs repository". I understand that repository is easier to test, and the CRUD logic is separate from the object data, and that separation makes sense to me. But still.. it means you have to write a separate repository model for each entity. Is this right?
BTW - I know Codeigniter has a Database class and uses active record, and in a way I am just kind of re-creating it with some of those approaches. I'm just trying to understand things without relying on the framework internals. Any comments? Is it just a matter of choice?
Trying to do a little research on my own, thanks to your question, I came across this article: http://msdn.microsoft.com/en-us/magazine/dd569757.aspx , which explains the differences between different data access patterns.
I hope i understood the question correctly, but here goes.
My approach would be to use the separation of models, however the one twist i usually do. i will try to be clear.
Lets say my application is going to require 3 unique features. One for users, facts, sources, All of these models might need to use some common functions like SAVE or LOAD, or UPDATE, or DELETE. Instead of duplicating the common functions into each model, i would simply make a base class with all the common functions, a nd have the base class extend the CI_Model, then all my new model files ( users,facts,sources ) i would have extend my common class.
To better illustrate this, i will throw some basic code up
db_common_model Common Class (db_common_model.php)
class db_common_model extends CI_Model
{
public function __construct()
{
parent::__construct();
}
/**
* All Common Functions Here */
public function save()
{
// Do stuff
}
public function update()
{
// Do stuff
}
public function etc()
{
// Do stuff
}
}
users_model Class (db_common_model.php)
class users_model extends db_common_model
{
public function __construct()
{
parent::__construct();
}
/**
* user specific functions */
public function get_one()
{
// Do stuff
}
public function get_all()
{
// Do stuff
}
public function get_latest()
{
// Do stuff
}
public function etc()
{
// Do stuff
}
}
/**
* When using it in CI Controller
*/
$this->user_model->get_one(); // loads user specific function
$this->user_model->save(); // Calls all inherited methods from parent db_common_model
// Etc
This way of setting up your models allows you expand common features in the db_common_model, that are automatically available to all children classes.
This allows for clean organization, and allows you to not have to re-invent your common functions in every model.
Hope this helps.