Laravel 5 单元测试 - 在 null 上调用成员函数 connection()

Posted

技术标签:

【中文标题】Laravel 5 单元测试 - 在 null 上调用成员函数 connection()【英文标题】:Laravel 5 Unit Test - Call to a member function connection() on null 【发布时间】:2017-07-19 15:44:15 【问题描述】:

我尝试为我的UserShop 模型之间的关系创建一个单元测试,但是当我运行vendor\\bin\\phpunit 时会抛出这个错误,因为我是新手,所以我对此一无所知在单元测试中。我试图在我的控制器上运行我的代码以查看关系是否真的有效,幸运的是它按预期工作,但在 phpunit 中运行时却没有。我做错了什么让这个 phpunit 不能与模型一起工作?

Fatal error: Uncaught Error: Call to a member function connection() on null in E:\projects\try\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php:1013

Stack trace: E:\projects\try\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(979): Illuminate\Database\Eloquent\Model::resolveConnection(NULL)

这是我的 UserTest.php

<?php

namespace Tests\Unit;

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

use App\User;
use App\Shop;

class UserTest extends TestCase


    protected $user, $shop;

    function __construct()
    
        $this->setUp();
    
    
    function setUp()
    
        $user = new User([
            'id' => 1,
            'first_name' => 'John',
            'last_name' => 'Doe',
            'email' => 'JohnDoe@example.com',
            'password' => 'secret',
            'facebook_id' => null,
            'type' => 'customer',
            'confirmation_code' => null,
            'newsletter_subscription' => 0,
            'last_online' => null,
            'telephone' => null,
            'mobile' => null,
            'social_security_id' => null,
            'address_1' => null,
            'address_2' => null,
            'city' => null,
            'zip_code' => null,
            'signed_agreement' => 0,
            'is_email_confirmed' => 0
        ]);

        $user = User::find(1);
        $shop = new Shop([
            'id' => 1,
            'user_id' => $user->id,
            'name' => 'PureFoods Hotdog2',
            'description' => 'Something that describes this shop',
            'url' => null,
            'currency' => 'USD'
        ]);
        $user->shops()->save($shop);

        $shop = new Shop([
            'id' => 2,
            'user_id' => $user->id,
            'name' => 'PureFoods Hotdog',
            'description' => 'Something that describes this shop',
            'url' => null,
            'currency' => 'USD'
        ]);

        $user->shops()->save($shop);

        $this->user = $user;

    

    /** @test */
    public function a_user_has_an_id()
        $user =  User::find(1);
        $this->assertEquals(1, $user->id);
    

    /** @test */
    public function a_user_has_a_first_name()
    
        $this->assertEquals("John", $this->user->first_name);
    

    /** @test */
    public function a_user_can_own_multiple_shops()
    
        $shops = User::find(1)->shops()->get();
        var_dump($this->shops);
        $this->assertCount(2, $shops);
    

看来,这个错误是由这行代码引起的: $user-&gt;shops()-&gt;save($shop); - 此代码在我的示例路由或控制器中运行时实际上有效,但在 phpunit 中运行时抛出 errors

User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable

    use Notifiable;

    protected $guarded = [ 'id' ];
    protected $table = "users";   

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];


    /**
     * returns the Shops that this user owned
     */
    public function shops()
    
        return $this->hasMany('App\Shop');
    

Shop.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Shop extends Model

    protected $guarded = [ 'id' ];
    protected $table = "shops";

    /**
     * returns the Owner of this Shop
     */
    public function owner()
    
        return $this->belongsTo('App\User');
    

任何帮助将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

首先,setUp() 在每次测试之前被调用,所以你不应该在构造函数中调用它

其次,您应该调用 setUp() 中的 parent::setUp() 来初始化应用实例。

【讨论】:

【参考方案2】:

您将 id '2' 分配给两个商店。

分配 is 不是必须的,因为我假设 shop table id 字段是一个自动增量字段。

还可以查看database factories in the Laravel docs,它会为您简化事情。

【讨论】:

【参考方案3】:

示例:

<?php

class ExampleTest extends TestCase

  private $user;

  public function setUp()
  
    parent::setUp();

    $this->user = \App\User::first();
  

   public function testExample()
   
      $this->assertEquals('victor@castrocontreras.com', $this->user->email);
   

【讨论】:

【参考方案4】:

问题的原因:你不能使用在类 UserTest 的构造函数中调用的代码中的 Laravel 模型功能 - 即使你把代码放在方法“setUp”中,你也没有必要调用它从构造函数。 SetUp 由 phpUnit 调用,无需在构造函数中进行。

当 UserTest 构造函数运行时,Laravel Bootstrap 代码还没有被调用。

当调用 UserTest->setUp() 方法时,Laravel Bootstrap 代码已经运行,所以你可以使用你的模型等。

class UserTest extends TestCase
protected $user, $shop;

function __construct()

    $this->setUp(); // **THIS IS THE PROBLEM LINE**


function setUp()

    $user = new User([....

【讨论】:

【参考方案5】:

当您尝试从 dataprovider 函数读取数据库时,可能会发生这种情况。像我试过的,是的。工作方式:

protected static $tariffs_default;
protected function setUp(): void 
    parent::setUp ();
    if (!static::$tariffs_default)
        static::$tariffs_default = DB::...;
    
    
// in dataprovider we use string parm, named as our static vars
public static function provider_prov2()
    return [
        [".....", [ 'tariffs'=>'tariffs_default'] ],
    ];

// then, in test we can ask our data by code:
public function testSome(string $inn, string $ogrn, $resp_body)
    if ( $ta_var = Arr::get( $resp_body, 'tariffs' ) )
        Arr::set($resp_body, 'tariffs', static::$$ta_var );
    
    $this->assert...

【讨论】:

谢谢。这就是发生在我身上的原因。在我发现这个之前,我看起来很困惑。【参考方案6】:

还有一个原因

检查测试类是否在扩展 use Tests\TestCase; 而不是 use PHPUnit\Framework\TestCase;

Laravel 附带了后者,但 Tests\TestCase 类负责设置应用程序,否则模型在扩展 PHPunit\Framework\ 时将无法与数据库通信测试用例

【讨论】:

(它说要避免这种类型的 cmets...)但是谢谢!!!!!!。我已经坚持了 2 天了!!!!!!! 但是我对此有点困惑,为什么默认样板使用 PHPUnit\Framework\TestCase 呢?为什么要使用 Tests\TestCase 的替代品? 对于基本测试,我认为您不会想要设置 Tests\TestCase 所做的应用程序。我认为这就是我不确定的原因。你可以问问 laravel 团队。【参考方案7】:

解决方案

使用 PHPunit\Framework\TestCase

放这个

使用测试\TestCase

【讨论】:

似乎this的重复答案

以上是关于Laravel 5 单元测试 - 在 null 上调用成员函数 connection()的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5.5 中 PHP 单元测试中的类验证器错误

在 laravel 5.2 单元测试中模拟作业

在laravel 5.1单元测试中嘲笑hasMany关系

Laravel 单元测试迁移失败

使用 Mock 对 Laravel 5 Mail 进行单元测试

Laravel 5.1 Eloquent isFillable() 单元测试中的差异