Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Controller Layout testing

I'm trying to include unit-testing in a new Laravel app I'm building. Right now I'm want to test my OrderController. The index method of this controller looks like this:

public function index()
{
    // We need the extra 'orders()' for the query scope
    $orders = $this->order->orders()->paginate($this->perPage);

    $this->layout->content = View::make('orders.index', compact('orders'));
}

Now I have my test that looks like this:

public function testIndex()
{
    $this->call('GET', 'orders');

    $this->assertResponseOk();

    $this->assertViewHas('orders');
}

Now if I run phpunit, the test does run, but I'm getting: 1) OrderControllerTest::testIndex Failed asserting that an array has the key 'orders'.

I've tracked down the issue to using Controller Layouts $this->layout. If I just do return View::make() the test does pass, if I return $this->layout... it also does pass, but this destroys the actual app.

So only option I've found is to use return View::make() and have @extends('master') in that view. But it's seems strange to me that you can't use Controller Layouts in your app if you want to test it.

Am I doing something wrong?

like image 483
Crinsane Avatar asked Apr 15 '26 03:04

Crinsane


1 Answers

Edit: I had the same problem and here is slightly messy solution that works!

    View::composer('ordersviewname', function($view) {
      $this->assertArrayHasKey('orders', $view->getData());
    });

    $this->call('GET', 'orders');

Note that you have to put this code BEFORE $this->call()

EDIT: Here is more elegant solution! Add functions to TestCase

    protected $nestedViewData = array();

    public function registerNestedView($view)
    {
      View::composer($view, function($view){
        $this->nestedViewsData[$view->getName()] = $view->getData();
      }); 
    }

    /**
     * Assert that the given view has a given piece of bound data.
     *
     * @param  string|array  $key
     * @param  mixed  $value
     * @return void
     */
    public function assertNestedViewHas($view, $key, $value = null)
    {
        if (is_array($key)) return $this->assertNestedViewHasAll($view, $key);

        if ( ! isset($this->nestedViewsData[$view]))
        {
            return $this->assertTrue(false, 'The view was not called.');
        }

        $data = $this->nestedViewsData[$view];

        if (is_null($value))
        {
            $this->assertArrayHasKey($key, $data);
        }
        else
        {
            if(isset($data[$key]))
              $this->assertEquals($value, $data[$key]);
            else 
              return $this->assertTrue(false, 'The View has no bound data with this key.');            
        }
    }

    /**
     * Assert that the view has a given list of bound data.
     *
     * @param  array  $bindings
     * @return void
     */
    public function assertNestedViewHasAll($view, array $bindings)
    {
        foreach ($bindings as $key => $value)
        {
            if (is_int($key))
            {
                $this->assertNestedViewHas($view, $value);
            }
            else
            {
                $this->assertNestedViewHas($view, $key, $value);
            }
        }
    }

    public function assertNestedView($view)
    {
      $this->assertArrayHasKey($view, $this->nestedViewsData);
    }

Now you would rewrite your test

$view='orders';
$this->registerNestedView($view);

$this->call('GET', 'orders');

$this->assertNestedViewHas($view, 'orders');

assertNestedViewHas() has all the same feautures as assertViewHas() !

I added another function assertNestedView() which just check if given view was called.

like image 76
neyl Avatar answered Apr 17 '26 15:04

neyl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!