【问题标题】:Laravel Unit testing Eloquent insertionLaravel 单元测试 Eloquent 插入
【发布时间】:2023-03-08 09:29:01
【问题描述】:

我目前在 Laravel 中测试函数时遇到了一些麻烦。这个函数是一个简单的保存用户函数。

当前结构涉及一个用户

class User extends Authenticatable

然后我有一个用户控制器

class UserController extends Controller
{
protected $user;

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

保存函数是在UserController类上定义的,该类只分配请求变量,使用Eloquent保存函数保存到数据库。

函数签名如下:

public function storeUser($request)
{

    $this->user->name       = $request->name;
    $this->user->email      = $request->email;
    $this->user->country_id = $request->country_id;

    return $this->user->save();
}

NewAccountRequest 对象从 Request 扩展而来,并具有请求的验证规则。

class NewAccountRequest extends Request
{
public function authorize()
{
    return true;
}

public function rules()
{
    return [
        'name' => 'required|max:255',
        'email' => 'required|email|max:255|unique:user',
        'password' => 'required|min:6|max:60',
    ];
}

}

我的问题是如何对这个 storeUser 函数进行单元测试。

我有当前的测试:

public function testSaveUserWithEmptyRequest()
{

    $user = $this->createMock(User::class);
    $controller = new UserController($user);

    $request = $this->createMock(NewAccountRequest::class);
    $store = $controller->storeUser($request);

    $this->assertFalse($store);
}

我在嘲笑 User 和 NewAccountRequest,问题是断言应该是错误的,来自 Eloquent 保存。相反,我得到了 Null。关于如何正确测试该功能的任何想法?

【问题讨论】:

  • saveUser 函数里面有什么,你是否缺少返回语句?
  • @ShadyAtef 使用 StoreUser 代码更新了问题并更正了呼叫名称。
  • 我明白了,你模拟了User::class.. 在 PHPUnit 中,createMock 将对象的所有函数替换为不执行任何操作并返回空值的虚拟函数。事实上,要在 laravel 中测试数据库操作,您必须使用 DatabaseMigrationsDatabaseTransactions 提供的两个特征之一
  • 但是我不是在嘲笑UserController,它不应该因为请求为空而返回false吗?
  • 但是返回行只是在$user 上调用了一个你已经模拟并传递的函数

标签: php laravel unit-testing laravel-5 phpunit


【解决方案1】:
<?php
namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class ExampleTest extends TestCase
{
    use DatabaseTransactions; // Laravel will automatically roll back changes that happens in every test 


    public function testSaveUserWithEmptyRequest()
    {

        $user = new User(); 
        $controller = new UserController($user);

        $request = $this->createMock(NewAccountRequest::class);
        $store = $controller->storeUser($request);

        $this->assertFalse($store);
    }

}

这正是您想要做的,但不幸的是,由于数据库异常,这将失败...... 模拟请求甚至手动制作它都不会进行数据输入验证。在您的示例中,password 字段不可为空,并且会导致 PDOException: SQLSTATE[HY000]: General error: 1364 Field 'password' doesn't have a default value


根据请求测试功能的推荐方法是使用 laravel 提供的 http 测试助手,例如 $response = $this-&gt;post('/user', ['name' =&gt; 'Sally']);


更好的方法是使用存储库设计模式。这只是意味着将您的数据库函数整理到单独的类中并从控制器中调用它..

【讨论】:

  • 将尝试使用路线进行测试,当我这样做时会给出反馈。谢谢!
  • 哦还有点我忘了说,你在测试开始时尝试$this-&gt;expectException(\PDOException::class); 来捕获抛出的异常。
猜你喜欢
  • 2015-06-25
  • 1970-01-01
  • 2015-09-12
  • 2019-08-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 2018-03-11
相关资源
最近更新 更多