1

I just started with learning how to test within Laravel. I came across some problems though.. I'm testing my controller and want to check if a View has a variable assigned.

My controller code:

class PagesController extends \BaseController {

   protected $post;

   public function __construct(Post $post) {
      $this->post = $post;
   }

   public function index() {
      $posts = $this->post->all();
      return View::make('hello', ['posts' => $posts]);
   }
}

And my view contains a foreach loop to display all posts:

@foreach ($posts as $post)
   {{post->id}}
@endforeach

Last but not least my test file:

class PostControllerTest extends TestCase {

public function __construct()
{
    // We have no interest in testing Eloquent
    $this->mock = Mockery::mock('Eloquent', 'Post');
}

public function tearDown()
{
    Mockery::close();
}

public function testIndex() {

    $this->mock->shouldReceive('all')->once()->andReturn('foo');
    $this->app->instance('Post', $this->mock);
    $this->call('GET', '/');
    $this->assertViewHas('posts');

}

}

Now comes the problem, when I run "phpunit" the following error appears:

ErrorException: Invalid argument supplied for foreach()

Any ideas why phpunit returns this error?

2 Answers 2

2

Your problem is here:

$this->mock->shouldReceive('all')->once()->andReturn('foo');

$this->post->all() (which is what you're mocking) should return an array, and that's what your view expects. You're returning a string.

$this->mock->shouldReceive('all')->once()->andReturn(array('foo'));

should take care of the error you have, though you'll then get an error of the "Getting property of non-object" type.

You could do this:

$mockPost = new stdClass();
$mockPost->id = 1;
$this->mock->shouldReceive('all')->once()->andReturn(array($mockpost));
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! This works, but only when I add {{posts}} it gives the error: Array to string conversion. Is there a way to solve this too?
I used FactoryMuff for creating a quick post like so: $mockPost = FactoryMuff::create('Post'); Yet this doesn't solve the problem when I'm calling {{$posts}} but it does populate all the other fields of Post (such as body).
You can't just echo {{posts}} because it's an array -- you need to loop over it and echo individual entries, as in the code in your question.
Ah I'm sorry.. laravel converts arrays to json when you do {{$posts}} and thats not done in my test. Thanks anyways, my bad there ;)
0

You should mock the view as well:

public function testIndex() {
    $this->mock->shouldReceive('all')->once()->andReturn('foo');
    $this->app->instance('Post', $this->mock);
    View::shouldReceive('make')->with('hello', array('posts', 'foo'))->once();
    $this->call('GET', '/');
}

5 Comments

This doesn't work for me. It returns the following error:ErrorException: Trying to get property of non-object
I fixed it up. Ignore the original answer, just do this
did you switch the mock of your model back to what you originally had in your code? i.e. it should be back to $this->mock->shouldReceive('all')->once()->andReturn('foo'); - not the array anymore...?
This doesnt work either. Error: Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_1_Illuminate_View_Factory::make("hello", array('posts'=>'foo',)). Either the method was unexpected or its arguments matched no expected argument list for this method
yes I did exactly as you said in your updated answer. The test succeeds if I replace @foreach etc. with {{posts}}, with my code. It has to do something with the foreach or something.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.