segunda-feira, 7 de novembro de 2016

Testing Repository with Laravel and Mockery

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

Nenhum comentário:

Postar um comentário