mocking out database queries laravel mockery mocking out database queries laravel mockery laravel laravel

mocking out database queries laravel mockery


You should have Product injected via the constructor so Laravel can handle that for you.

use App\Models\Product;class SoldProductModifier {    private $sold_product;    protected $product;    public function __construct(SoldProduct $sold_product, Product $product)     {        $this->sold_product = $sold_product;        $this->product = $product;    }}

Now you need to write one unit test for each "path" through the function.

// Build your mock object.$mockProduct = Mockery::mock(new App\Models\Product);// Have Laravel return the mocked object instead of the actual model.$this->app->instance('App\Models\Product', $mockProduct);// Tell your mocked instance what methods it should receive.$mockProduct    ->shouldReceive('findByItemCode')    ->once()    ->andReturn(false);// Now you can instantiate your class and call the methods on it to be sure it's returning items and setting class properties correctly.

You should write this test multiple times and have your $mockProduct return different things until all lines of code have been covered. For example, you might want to do something like the following...

$product = new stdClass;$product->id = 45;$category = new stdClass;$category-id = 60;$product->category = $category;$mockProduct    ->shouldReceive('findByItemCode')    ->once()    ->andReturn($product);

Now after the function runs, you'd want to make sure sold_product->category_id is equal to 60 and sold_product->product_id is equal to 45. If they are private and you can't check them from the test, you might want to write a getter for those objects so you can more easily see their values from the test.

Edit

Regarding your comments, you'd use the following.

new SoldProductModifier($sold_product, new Product);

And then your function should look like...

public function modifyBasedOnItemCode($item_code){    if (! isset($item_code) || $item_code == '')    {        $product = $this->product->findByItemCode($item_code);        if (isset($product) && $product != false)        {            $this->sold_product->category_id = $product->category->id;            $this->sold_product->product_id = $product->id;        }    }    return $this->sold_product;}

I see that it's a static function so you may want to handle that a bit differently. If it's static just for this reason, then you can simply not make it static. If other things are depending on it, you can likely make a new function which isn't static which calls the static function via self::findByItemCode($id)

The general rule of thumb here is unless it's a facade which has been setup in your config.php file, you should allow Laravel to handle injecting it for you. That way when you are testing, you can create mock objects and then let Laravel know about them via $this->app->instance() so it will inject those in place of the real ones.