是否有必要测试双向关系?

时间:2013-12-16 22:28:35

标签: php unit-testing laravel phpunit ardent

我正在尝试test relationships between models使用ArdentFactoryMuff。我能够在belongs_to方向测试关系,但我无法在has_many方向测试它。

我正在测试的模型是住宅房地产租赁应用程序,它是相应的租赁历史记录。一个非常简化的数据库模式:

+--------------+
| applications |
+--------------+
| id           |
| name         |
| birthday     |
| income       |
+--------------+

+----------------+
| history        |
+----------------+
| id             |
| application_id |
| address        |
| rent           |
+----------------+

这是我的历史模型:

class History extends Ardent
{
    protected $table = 'history';

    public static $factory = array(
        'application_id' => 'factory|Application',
        'address' => 'string',
        'rent' => 'string',
    );

    public function application()
    {
        return $this->belongsTo('Application');
    }
}

这是我的测试,以确保历史对象属于租赁应用程序:

class HistoryTest extends TestCase
{
    public function testRelationWithApplication()
    {
        // create a test rental history object
        $history = FactoryMuff::create('History');

        // make sure the foreign key matches the primary key
        $this->assertEquals($history->application_id, $history->application->id);
    }

}

这很好用。但是,我无法弄清楚如何在另一个方向上测试这种关系。在项目要求中,租赁应用程序必须至少有一个与之关联的租赁历史记录对象。这是我的应用程序模型:

class Application extends Ardent
{
    public static $rules = array(
        'name' => 'string',
        'birthday' => 'call|makeDate',
        'income' => 'string',
    );

    public function history()
    {
        return $this->hasMany('History');
    }

    public static function makeDate()
    {
        $faker = \Faker\Factory::create();
        return $faker->date;
    }
}

这就是我试图测试has_many关系的方式:

class ApplicationTest extends TestCase
{
    public function testRelationWithHistory()
    {
        // create a test rental application object
        $application = FactoryMuff::create('Application');

        // make sure the foreign key matches the primary key
        $this->assertEquals($application->id, $application->history->application_id);
    }
}

当我运行单元测试时,这会导致ErrorException: Undefined property: Illuminate\Database\Eloquent\Collection::$application_id 。对于我,这说得通。我告诉FactoryMuff无处创建至少一个相应的History对象以与我的Application对象一起使用。我也没有编写任何代码来强制要求Application对象必须至少有一个History对象。

问题

  1. 如何强制执行规则“application对象必须至少有一个history对象”?
  2. 如何测试关系的has_many方向?

1 个答案:

答案 0 :(得分:1)

是的,您应该始终在两个方向上测试关系,因为您可能需要分别从两端访问每个模型。

至于强制执行,没有我所知道的编程方式,当你使用has()方法调用模型时,你必须内联:

$application = Application::find($id)->has('history', '>=', 1)->get();

现在hasMany()关系将返回一个集合,因此您实际上是在尝试访问Collection实例上的application_id属性。

你有两个选择来测试它,第一个是循环和assertEquals,如下所示:

foreach($application->history as $history) {
    $this->assertEquals($application->id, $history->application_id);
}

现在,既然您正在测试,并且创建的模型的实例是出于测试目的,那么可能值得做类似以下的事情:

$history = $application->history->first();
$this->assertEquals($application->id, $history->application_id);

重申一下,问题是如果找到子关系,hasMany()关系将始终返回Illuminate \ Database \ Eloquent \ Collection的实例,即使只有一个,但上述两种方法应该足以满足您的要求需要。希望有所帮助。

P.S:我的示例不包括验证以确保变量不为空等等,可能值得将其添加到您的测试中。

- 更新 -

不幸的是,我不熟悉FactoryMuff,虽然如果它以我认为的方式工作,你应该能够在你的测试中做到以下几点:

$application = FactoryMuff::create('Application');
$history = FactoryMuff::create('History');
$application->history()->save($history);

如果你指的是实际的应用程序代码,你可以直接进入模型事件并添加一个新的History对象。