【问题标题】:Laravel Controller Layout testingLaravel 控制器布局测试
【发布时间】:2013-05-12 12:28:09
【问题描述】:

我正在尝试在我正在构建的新 Laravel 应用程序中包含单元测试。 现在我想测试我的 OrderController。该控制器的 index 方法如下所示:

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'));
}

现在我的测试看起来像这样:

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

    $this->assertResponseOk();

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

现在如果我运行 phpunit,测试确实会运行,但我得到:1) OrderControllerTest::testIndex Failed asserting that an array has the key 'orders'.

我已经找到了使用控制器布局$this->layout 的问题。 如果我只是做return View::make() 测试确实通过了,如果我返回$this->layout... 它也确实通过了,但这会破坏实际的应用程序。

所以我发现的唯一选择是使用return View::make() 并在该视图中使用@extends('master')。但是如果你想测试它,你不能在你的应用程序中使用控制器布局,这对我来说似乎很奇怪。

我做错了吗?

【问题讨论】:

  • 测试失败的原因是因为Orders.Index视图被渲染到了布局中,所以到你测试的时候,orders变量已经渲染出来了,不再存在了。我不确定最好的测试方法是什么......您可以检查 orders.index 视图是否在单独的测试中包含 orders 变量,然后检查组合视图是否包含“内容”变量,但这就是我的全部能想到。

标签: php unit-testing controller laravel laravel-4


【解决方案1】:

编辑: 我遇到了同样的问题,这里有一个有点混乱的解决方案!

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

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

请注意,您必须将此代码放在$this->call()之前

编辑: 这是更优雅的解决方案! 向 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);
    }

现在你将重写你的测试

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

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

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

assertNestedViewHas()assertViewHas() 具有所有相同的功能!

我添加了另一个函数assertNestedView(),它只是检查是否调用了给定的视图。

【讨论】:

  • +1 - 这是一个很好的解决方案,现在可以使用模板 TDD。您应该考虑将此作为对 Laravel 4.1 的建议提出
  • 非常优雅的解决方案。我肯定会考虑为 laravel 4.1 添加建议
猜你喜欢
  • 2015-03-12
  • 2011-11-07
  • 2016-12-30
  • 2020-08-12
  • 2018-03-09
  • 2019-06-19
  • 1970-01-01
  • 2014-09-13
  • 2021-12-11
相关资源
最近更新 更多