Laravel Eloquent模型单元测试

时间:2015-04-18 10:05:12

标签: laravel laravel-4 phpunit eloquent

我正在尝试编写一个测试用例,用于测试Laravel 4.2中两个Eloquent模型之间关系的关联和分离

这是我的测试用例:

class BookingStatusSchemaTest extends TestCase
{

  private $statusText = "Confirmed";
  private $bookingStub;
  private $statusStub;

  public function testMigrateService()
  {

    $this->createTestData();

    $booking = $this->bookingStub;
    $status = $this->statusStub;

    /**
     * Check that the booking has no status. OK
     */
    $this->assertNull($booking->status);

    /**
     * Check that status has no booking. OK
     */
    $this->assertEquals(count($status->bookings), 0);

    /**
     * Add a status to the booking. OK
     */
    $booking->status()->associate($this->statusStub);

    /**
     * Check that status has a booking. NOT OK - This gives error
     */
    $this->assertEquals(count($status->bookings), 1);

    /**
     * Check that the booking has a status. OK
     */
    $this->assertNotNull($booking->status);

    /**
     * Do NOT delete the status, just set the reference
     * to it to null.
     */
    $booking->status = null;

    /**
     * And check again. OK
     */
    $this->assertNull($booking->status);
  }

  private function createTestData()
  {

    $bookingStatus = BookingStatus::create([ 
        'status' => $this->statusText 
    ]);

    $booking = Booking::create([ ]);

    $this->bookingStub = $booking;
    $this->statusStub = $bookingStatus;

  }

}

当我执行它时,我得到:

There was 1 failure:

1) BookingStatusSchemaTest::testMigrateService
Failed asserting that 1 matches expected 0.

预订模式:

class Booking extends Eloquent {

  /**
  * A booking have a status
  */
  public function status()
  {
    return $this->belongsTo('BookingStatus');
  }

}

BookingStatus模型:

class BookingStatus extends Eloquent
{
  protected $table = 'booking_statuses';
  protected $guarded = [ 'id' ];
  protected $fillable = ['status'];

  /**
   * A booking status belongs to a booking
   */
  public function bookings()
  {
    return $this->hasMany('Booking');
  }

}

以下是bookingstatus的迁移架构:

  Schema::create('booking_statuses', function(Blueprint $table)
  {
    $table->increments('id');
    $table->string('status');
    $table->timestamps();
  });

而且他是预订的:

Schema::create('bookings', function(Blueprint $table)
{
  $table->increments('id');
  $table->unsignedInteger('booking_status_id')->nullable();
  $table->timestamps();
});

我需要添加/更改哪些内容才能验证测试用例中的关系?

2 个答案:

答案 0 :(得分:5)

  

已经有一段时间了,我完全忘记了这个问题。   由于OP仍然对它感兴趣,我会尝试回答这个问题   以某种方式。

所以我假设实际的任务是:如何测试两个Eloquent模型之间的正确关系?

我认为是Adam Wathan首先建议放弃像#34; Unit Tests"和"功能测试"并且"我不知道 - 这是什么意思测试"并且只是将测试分成两个问题/概念:功能和单位,其中功能只是描述应用程序的功能,例如"登录用户可以预订机票"和单位描述它的较低级单位以及他们公开的功能,例如"预订具有状态"。

我非常喜欢这种方法,考虑到这一点,我想重构你的测试:

class BookingStatusSchemaTest extends TestCase
{
    /** @test */
    public function a_booking_has_a_status()
    {
        // Create the world: there is a booking with an associated status
        $bookingStatus = BookingStatus::create(['status' => 'confirmed']);
        $booking = Booking::create(['booking_status_id' => $bookingStatus->id]);

        // Act: get the status of a booking
        $actualStatus = $booking->status;

        // Assert: Is the status I got the one I expected to get?
        $this->assertEquals($actualStatus->id, $bookingStatus->id);
    }


    /** @test */    
    public function the_status_of_a_booking_can_be_revoked()
    {
        // Create the world: there is a booking with an associated status
        $bookingStatus = BookingStatus::create(['status' => 'confirmed']);
        $booking = Booking::create(['booking_status_id' => $bookingStatus->id]);

        // Act: Revoke the status of a booking, e.g. set it to null
        $booking->revokeStatus();

        // Assert: The Status should be null now
        $this->assertNull($booking->status);
    }
}

此代码未经过测试!

请注意函数名称如何读取,如预订说明及其功能。您并不真正关心实施,您不必知道预订在何处或如何获得BookingStatus - 您只是想确保如果预订有BookingStatus,您可以获得BookingStatus 。或者撤销它。或者也许改变它。或者做任何事情。您的测试显示了您希望如何与此单元进行互动。所以写下测试然后尝试让它通过。

你测试中的主要缺陷可能是你有点害怕"一些神奇的事情发生。相反,将您的模型视为普通的旧PHP对象 - 因为它们是什么!而且你不会在POPO上进行这样的测试:

/**
 * Do NOT delete the status, just set the reference
 * to it to null.
 */
$booking->status = null;

/**
 * And check again. OK
 */
$this->assertNull($booking->status);

这是一个非常广泛的话题,关于它的每一个陈述都不可避免地被贬低。有一些指导方针可以帮助你相处,比如只测试你自己的代码"但是很难把所有的和平放在一起。幸运的是,前面提到的Adam Wathan有一个非常优秀的视频课程,名为" Test Driven Laravel"他在那里测试驱动整个真实世界的Laravel应用程序。它可能有点贵,但它值得每一分钱,并帮助你理解测试方式比StackOverflow上的一些随机的人更多:)

答案 1 :(得分:1)

要测试您是否设置了正确的口才关系,您必须针对关系类($model->relation())运行断言。 您可以断言

  • 通过断言$model->relation()HasManyBelongsToHasManyThrough ...的实例,这是正确的关系类型
  • 通过使用$model->relation()->getRelated()来与正确的模型有关
  • 它通过使用$model->relation()->getForeignKey()
  • 使用了正确的外键
  • 通过使用Schema::getColumListing($table),外键在表中作为一列存在(此处,$table$model->relation()->getRelated()->getTable()(如果是HasMany关系,或者是$model->relation()->getParent()->getTable()如果是BelongsTo关系)

例如。假设您有一个ParentChild模型,其中Parent通过Child方法使用children()作为外部变量,通过parent_id有很多Parent键。 parents映射Child表,而children映射$parent = new Parent; # App\Parent $parent->children() # Illuminate\Database\Eloquent\Relations\HasMany $parent->children()->getRelated() # App\Child $parent->children()->getForeignKey() # 'parent_id' $parent->children()->getRelated()->getTable() # 'children' Schema::getColumnListing($parent->children()->getRelated()->getTable()) # ['id', 'parent_id', 'col1', 'col2', ...] 表。

serviceSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
serviceSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

ip = socket.gethostbyname(socket.gethostname()).split(".")
ip = "{}.{}.{}.255".format(ip[0],ip[1],ip[2])

HOST = ip
PORT = 5000
soket.bind((HOST,PORT))

编辑 而且,这不会影响数据库,因为我们从不保存任何内容。但是,数据库需要迁移,否则模型将不与任何表关联。