这个模拟对象上不存在方法 - Laravel,Mockery
Posted
技术标签:
【中文标题】这个模拟对象上不存在方法 - Laravel,Mockery【英文标题】:method does not exist on this mock object - Laravel , Mockery 【发布时间】:2015-03-01 01:41:48 【问题描述】:我正在尝试测试一个简单的类。我正在关注本教程(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');
我的 EloquentMealTypeRepository: 没有什么真正有趣的。
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'] );
我的 MealTypeRepositoryInterface:
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
,并且
您的任何模拟都没有采用您的主题的任何方法,并且
正在自动加载您的类(例如,使用 composer)
然后在制作模拟对象之前,您需要使用以下代码行强制加载该主题:
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');
我现在已经忘记了 3 次了,每次都花一两个小时想知道到底是什么问题!
【讨论】:
【参考方案2】:我在控制器中找到了这个错误的来源。 叫错了
$v = $mealType->getValidator($input);
而不是正确的
$v = $this->mealType->getValidator($input);
【讨论】:
以上是关于这个模拟对象上不存在方法 - Laravel,Mockery的主要内容,如果未能解决你的问题,请参考以下文章
Laravel - 此集合实例上不存在属性 [fileieres]
Laravel 8 Seeders:此集合实例上不存在属性 [id]
Laravel/Eloquent belongsToMany - Eloquent 构建器实例上不存在属性 [人]