【发布时间】:2021-11-30 18:49:41
【问题描述】:
附: 起初我问如何模拟 Model::create,但我想做的是编写一个测试,当 try 发生错误时,它会正确地进入 catch。
感谢@matiaslauriti 的评论,我找到了更好的方法,所以我将把我的问题从如何模拟改为如何编写测试。
详情请看答案部分和cmets。
·········
我有这个代码。
class MyModel extends Model
{
public static function addRecord()
{
//...
try {
DB::beginTransaction();
foreach ($rows as $row) {
self::create([
'name' => $name,
'phone' => '',
]);
}
DB::commit();
} catch (\Exception $ex) {
DB::rollback();
throw($e);
}
}
}
这是我的测试代码。但是模拟返回错误并且测试不起作用。
class MyModelTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
$this->my_model = new MyModel();
}
/**
* @test
*/
public function addRecord_error()
{
$mock = \Mockery::mock(MyModel::class)->makePartial();
$mock->shouldReceive('create')
->once()
->andThrow(new \Exception());
$this->app->bind(MyModel::class, function () use ($mock) {
return $mock;
});
$my_model = app(MyModel::class);
//run method
$my_model->addRecord();
// ↑↑ This return error with
//BadMethodCallException:Static method
//Mockery_2_App_Models_MyModel::addRecord() does not exist on this mock object
//try {
//$my_model->addRecord();
//} catch (\Exception $ex) {
// $this->assertCount(0, MyModel::all());
//}
}
}
我想写一个测试,如果尝试失败,它会去捕获并调用回滚。
【问题讨论】:
-
首先,你正在使用
new MyModel();,你永远不会得到mock,因为你实际上是在使用new,所以你正在创建一个新实例......您需要做的是使用app(MyModel::class);或resolve(MyModel::class);(resolve是app的别名)。在声明期望后(在shouldReceive->....->....之后)并使用$this->app->bind(MyModel::class, $mock),而不是$this->instance,您必须使用这些助手中的任何一个。您还可以为第一部分设置“更好”的代码:laravel.com/docs/7.x/database#database-transactions -
@matiaslauriti 谢谢你的评论!我尝试按上述方式更改代码,但出现错误,而且似乎还没有通过模拟。还有什么我应该做的吗?也感谢您提供更好的代码。由于我只负责测试,所以我无法更改产品方法,但我会记住这一点。
-
让我添加一个答案
标签: unit-testing phpunit laravel-7 mockery