I was reading the awesome Taylor Otwell’s Book - Laravel From Apprentice To Artisan- https://leanpub.com/laravel and i’ll show some nice examples mixed with some code i did.
So, let’s do dependency Injection:
namespace App\Contracts;
interface ProductRepositoryInterface{
public function all();
}
Now our Repo:
<?php
namespace App\Repositories;
use App\Contracts\ProductRepositoryInterface;
use App\Product;
class ProductRepository implements ProductRepositoryInterface{
public function all(){
return Product::all()->toArray();
}
}
Now we can use the Repo:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Product;
use App\Contracts\ProductRepositoryInterface;
use Response;
class ProductController extends Controller
{
public function __construct(ProductRepositoryInterface $products){
$this->products = $products;
}
public function index(){
$products = $this->products->all();
return view('products.index', compact('products'));
}
}
Don’t forget the Routes!!!!
Now we can test:
<?php
use App\Product;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseTransactions;
public function tearDown(){
Mockery::close();
}
public function testIndexActionBindsProductsFromRepository(){
$mock = Mockery::mock('App\Contracts\ProductRepositoryInterface');
$mock->shouldReceive('all')->once()->andReturn(['lol', 'kk']);
App::instance('App\Contracts\ProductRepositoryInterface', $mock);
$response = $this->action('GET', 'ProductController@index');
$this->assertResponseOk();
$this->assertViewHas('products', ['lol', 'kk']);
}
}
We use DatabaseTransactions; to rollback the changes. In the test we mock our Interface and arrange telling that it gonna receive a call for all() and return array [‘lol’, ‘kk’]. Using App::instance we register that in the execution when the interface is requested it will throw our mock. With this we simulate a GET request with action(). The assertion is ok and our view has the array.
Now we’ll use the factory, in database > factories register the following:
$factory->define(App\Product::class, function (Faker\Generator $faker) {
return [
'title' => $faker->sentence
];
});
We used only the title for simplicity. Now we can do the following test:
public function testProductsCreationAndJsonList(){
factory(Product::class, 3)->create();
$response = $this->action('GET', 'ProductController@getProducts');
$this->assertResponseStatus(200);
}
With create() we insert 3 products in the database. With the action we simulate the request and assert the status. Now we put the getProducts():
public function getProducts(){
$products = $this->products->all();
//refactoring this -> next POST!!!! we gonna make a class to implement the return and extend
if (empty($products)){
$arrResponse = ['error' => ['message' => 'No Product found', 'code' => 'Internal Code']];
return Response::json($arrResponse, 404);
}
return Response::json(['data' => $products], 200);
}
In the next post we will refactor getProducts and extract a class. TY
References:
https://leanpub.com/laravel
https://laracasts.com/series/phpunit-testing-in-laravel
https://laravel.com/docs/5.2/mocking