方法在这个模拟对象上不存在 - 拉拉维尔,嘲弄


method does not exist on this mock object - Laravel , Mockery

我正在尝试测试一个简单的类。我正在遵循本教程(http://code.tutsplus.com/tutorials/testing-laravel-controllers--net-31456)。

我在运行测试时遇到此错误:

Method Mockery_0_App_Interfaces_MealTypeRepositoryInterface::getValidator() does not exist on this mock object

我使用存储库结构。因此,我的控制器调用存储库并返回 Eloquent 的响应。

我对php和laravel相对较新。几天前我已经开始学习测试了,所以我对那些混乱的代码感到抱歉。

我的测试用例:

class MealTypeControllerTest extends TestCase
{
public function setUp()
{
    parent::setUp();
    $this->mock = Mockery::mock('App'Interfaces'MealTypeRepositoryInterface');
    $this->app->instance('App'Interfaces'MealTypeRepositoryInterface' , $this->mock);
}
public function tearDown()
{
    Mockery::close();
}
public function testIndex()
{
    $this->mock
         ->shouldReceive('all')
         ->once()
         ->andReturn(['mealTypes' => (object)['id' => 1 , 'name' => 'jidlo']]);
    $this->call('GET' , 'mealType');
    $this->assertViewHas('mealTypes');
}
public function testStoreFails()
{
    $input = ['name' => 'x'];
    $this->mock
         ->shouldReceive('getValidator')
         ->once()
         ->andReturn(Mockery::mock(['fails' => true]));
    $this->mock
         ->shouldReceive('create')
         ->once()
         ->with($input);

    $this->call('POST' , 'mealType' , $input ); // this line throws the error
    $this->assertRedirectedToRoute('mealType.create');//->withErrors();
    $this->assertSessionHasErrors('name');
}
}

我的口才餐类型存储库:没什么有趣的。

class EloquentMealTypeRepository implements MealTypeRepositoryInterface
{
public function all()
{
    return MealType::all();
}
public function find($id)
{
    return MealType::find($id);
}
public function create($input)
{
    return MealType::create($input);
}
public function getValidator($input)
{
    return MealType::getValidator($input);
}
}

我雄辩的实现:也没有什么真正的插曲。

class MealType extends Model
{
private $validator;
/**
 * The database table used by the model.
 *
 * @var string
 */
protected $table = 'meal_types';
/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = ['name'];
/**
 * The attributes excluded from the model's JSON form.
 *
 * @var array
 */
protected $hidden = [];
public function meals()
{
    return $this->hasMany('Meal');
}
public static function getValidator($fields)
{
    return Validator::make($fields, ['name' => 'required|min:3'] );
}
}

我的膳食类型存储库接口:

interface MealTypeRepositoryInterface
{
public function all();
public function find($id);
public function create($input);
public function getValidator($input);
}

最后,我的控制器:

class MealTypeController extends Controller {
protected $mealType;
public function __construct(MealType $mealType)
{   
    $this->mealType = $mealType;
}

/**
 * Display a listing of the resource.
 *
 * @return Response
 */
public function index()
{
    $mealTypes = $this->mealType->all();
    return View::make('mealTypes.index')->with('mealTypes' ,$mealTypes);
}
/**
 * Show the form for creating a new resource.
 *
 * @return Response
 */
public function create()
{
    $mealType = new MealTypeEloquent;
    $action = 'MealTypeController@store';
    $method = 'POST';
    return View::make('mealTypes.create_edit', compact('mealType' , 'action' , 'method') );     
}
/**
 * Validator does not work properly in tests.
 * Store a newly created resource in storage.
 *
 * @return Response
 */
public function store(Request $request)
{
    $input = ['name' => $request->input('name')];
    $mealType = new $this->mealType;
    $v = $mealType->getValidator($input);
    if( $v->passes() )
    {
        $this->mealType->create($input);
        return Redirect::to('mealType');
    }
    else
    {
        $this->errors = $v;
        return Redirect::to('mealType/create')->withErrors($v);
    }
}
/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return Response
 */
public function show($id)
{
    return View::make('mealTypes.show' , ['mealType' => $this->mealType->find($id)]);
}
/**
 * Show the form for editing the specified resource.
 *
 * @param  int  $id
 * @return Response
 */
public function edit($id)
{
    $mealType = $this->mealType->find($id);
    $action = 'MealTypeController@update';
    $method = 'PATCH';
    return View::make('mealTypes.create_edit')->with(compact('mealType' , 'action' , 'method'));
}
/**
 * Update the specified resource in storage.
 *
 * @param  int  $id
 * @return Response
 */
public function update($id)
{
    $mealType = $this->mealType->find($id);
    $mealType->name = 'Input::get('name');
    $mealType->save();
    return redirect('mealType');
}
/**
 * Remove the specified resource from storage.
 *
 * @param  int  $id
 * @return Response
 */
public function destroy($id)
{
    $this->mealType->find($id)->delete();
    return redirect('mealType');
}
}

这应该是一切。值得一提的是,该应用程序有效,只是测试搞砸了。有谁知道,为什么会这样?我看不出TestCase的方法之间的区别 - testIndex 和testStoreFails,为什么找到方法"all"而"getValidator"没有。我将不胜感激任何建议。

也许是题外话,但与任何通过标题找到这个问题的人直接相关:

如果:

  1. 您收到错误BadMethodCallException: Method Mockery_0_MyClass::myMethod() does not exist on this mock object ,并且
  2. 你的模拟都没有拿起你受试者的任何方法,并且
  3. 您的类正在自动加载(例如,使用作曲家)

然后在创建模拟对象之前,您需要使用以下代码行强制加载该主题:

spl_autoload_call('MyNamespace'MyClass'); 

然后你可以模拟它:

$mock = 'Mockery::mock('MyNamespace'MyClass');

在我的 PHPUnit 测试中,我经常将第一行放入 setUpBeforeClass() 静态函数中,因此它只被调用一次,并且与添加/删除的测试隔离。所以 Test 类看起来像这样:

class MyClassTest extends PHPUnit_Framework_TestCase {
    public static function setUpBeforeClass() {
        parent::setUpBeforeClass();
        spl_autoload_call('Jodes'MyClass'); 
    }
    public function testIt(){
        $mock = 'Mockery::mock('Jodes'MyClass');
    }
}

我已经忘记了三次,每次都花一两个小时想知道问题到底是什么!

我在控制器中找到了此错误的来源。叫错了

$v = $mealType->getValidator($input);

而不是权利

$v = $this->mealType->getValidator($input);