Search code examples
unit-testinglaravelphpunitlaravel-4mockery

laravel phpunit mocked method requiring an array even when withAnyArgs() is called?


below is my controller class and the relevant method and my test class and relevant test. when the mocked method $this->user->update() runs I get this error

Time: 1.08 seconds, Memory: 31.00Mb

There was 1 error:

1) UserControllerTest::testUpdateSuccess
ErrorException: Argument 1 passed to Mockery_818785360_User::update() must be of
 the type array, string given, called in C:\Users\Mark\Dropbox\www\trainercompar
e\app\controllers\UsersController.php on line 134 and defined

shouldnt the mocked method take whatever arguments I send it unless otherwise defined? even if I change the mocked object method to include with(m::type'string') I get the same error. Ultimately the first argument will be a string and the second will be an array but I cant even get that far yet.

UserController.php

class UsersController extends BaseController {

    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }


    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id
     * @return Response
     */
    public function update($id)
    {
        $user = $this->user->find($id);

        if ($id == Auth::user()->id) {

            $input = Input::all();

            $validation = $this->user->validate($input);

            if ($validation->passes()) {

                $this->user->update(); 

            }


        }
        else {
            echo 'update failed';
        }
    }


}

UserControllerTest.php

<?php
    use Mockery as m;
    use Way\Tests\Factory;
class UserControllerTest extends TestCase {

    public function setUp()
    {
        parent::setUp();
        $this->mock = m::mock('Basemodel', 'User');
    }

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


    public function testUpdateSuccess()
    {
        $input = ['email' => '[email protected]',
                'password' => 'johndoepw',
                'firstName' => 'john',
                'secondName' => 'doe',
                'dob' => '1985-12-12',
                'height' => '187.96',
                'gender' => 'm',
                'phone' => '0877777777',
                'postcode' => '01',
                'addOne' => '29 black market',
                'addTwo' => 'malahide',
                'townCity' => 'Dublin',
                'county' => 'Dublin',
                'country' => 'Ireland'
                ];

        $userid = m::mock('userid');
        $userid->id = '1';
        $view = m::mock('viewret');
        $valmock = m::mock(['passes' => true]);

        Auth::shouldReceive('user')
            ->times(1)
            ->andReturn($userid);

        $this->mock
            ->shouldReceive('find')
            ->times(1)
            ->andReturn($userid->id);

        //Input::shouldReceive('all')->times(1);

        $this->mock
            ->shouldReceive('validate')
            ->times(1)
            ->andReturn($valmock);

        $this->mock
            ->shouldReceive('update')
            ->withAnyArgs()
            ->times(1);

        $this->app->instance('User', $this->mock);
        $this->call('Put', 'users/1', $input);
        $this->assertResponseOk();
    }

}

Solution

  • (mockery instance)->shouldReceive only validates the arguments after the function is run. So, in your controller code:

    if ($validation->passes()) {
      $this->user->update(); 
    }
    

    You're not actually passing anything to the update function. I'm assuming you want to pass in $input. so, it should be $this->user->update($input);

    I'm assuming that your instance of user has a method update that requires an array be passed.