提问人:cytsunny 提问时间:11/11/2023 更新时间:11/15/2023 访问量:150
如何在不保存到数据库的情况下在Laravel中分配belongsTo关系?
How to assign a belongsTo relation in Laravel without saving to database?
问:
我有以下 2 种型号:
<?php
namespace App\Models;
class Product extends Model
{
//some other property of the Model
public function productType() {
return $this->belongsTo( 'App\Models\ProductType', 'product_type_id');
}
public function theComplicatedFunctionBeingTested() {
//Some calculation with consideration of ProductType
return $result;
}
}
<?php
namespace App\Models;
class ProductType extends Model
{
//some other property of the Model
public function products() {
return $this->hasMany( 'App\Models\Product', 'product_id');
}
}
现在我想在模型中编写单元测试。如果没有必要,我不想模拟模型,所以我在单元测试中创建了这些模型的真实对象。theComplicatedFunctionBeingTested()
Product
<?php
use Illumniate\Foundation\Testing\TestCase;
use App\Models\Product;
use App\Models\ProductType;
class ProductFunctionTest extends TestCase
{
private $testProduct, $testProductType;
private function commonDataSetUp() {
$this->testProductType = new ProductType;
$this->testProductType->product_type_id = 1;
$this->testProductType->name = "publication";
$this->testProduct = new Product;
$this->testProduct->name = "testing product";
//I tried to assign a relation like this, but this is not working
$this->testProduct->productType = $this->testProductType;
}
public function testComplicatedProductFunction() {
$this->commonDataSetUp();
$result = $this->testProduct->theComplicatedFunctionBeingTested();
$this->assertEquals( 'my_expected_result', $result);
}
}
但是,关系设置不成功。由于未设置,Laravel 代码库的默认行为是尝试访问数据库,并且由于没有为单元测试设置数据库连接,因此会引发异常并且测试失败。$this->testProduct->productType
那么,在没有数据库的情况下,建立关系的正确方法应该是什么?
答:
-3赞
duckstery
11/11/2023
#1
您应该尝试此代码
$this->testProduct->setRelation("productType", $this->testProductType);
setRelation
记录在 Laravel 的 API 中 这里
评论
0赞
matiaslauriti
11/11/2023
这不是解决方案,他必须在测试中使用工厂
0赞
cytsunny
11/11/2023
我已经尝试过了,但它仍然不起作用。我相信只会在调用后设置关系。setRelation
save()
0赞
Khayam Khan
11/13/2023
#2
就像在评论中一样,我仍然认为你应该使用工厂,但如果你不想使用工厂,那么我认为这可能会对你有所帮助。 您可以通过 make 命令创建模型的实例,而无需将它们保存到数据库,如下所示:
$this->testProductType = ProductType::make([
// product type model columns
]);
$this->testProduct = Product::make([
// product model Columns
]);
,然后将 ProductType 与 Product 关联。
$this->testProduct->productType()->associate($this->testProductType);
我希望这可以解决您的问题。
评论
0赞
cytsunny
11/13/2023
我已经尝试了该函数,但如果不调用它就无法工作setRelation()
save()
0赞
Khayam Khan
11/13/2023
好的,然后尝试associate()
0赞
cytsunny
11/13/2023
我也试过了,但如果不打电话就不起作用save()
0赞
Khayam Khan
11/13/2023
那么我很抱歉,我不知道任何其他解决方案可能是其他人可能会回答更好的解决方案。
0赞
Win
11/15/2023
#3
由于关系是一对多,因此可以使用
- save() => 添加单个 ProductType,或者
- saveMany() => 添加多个 ProductType
在您的情况下,尝试在调用关系后使用 save()
$this->testProductType = new ProductType;
$this->testProductType->product_type_id = 1;
$this->testProductType->name = "publication";
$this->testProduct = new Product;
$this->testProduct->name = "testing product";
// You do need to save this first to gain product_id
$this->testProduct->save();
$this->testProduct->productType()->save($this->testProductType);
如果要添加 2 个或更多 ProductType,请尝试这样做
$this->testProduct->productType()->saveMany([
new ProductType(['name' => 'Abc']),
new ProductType(['name' => 'Def']),
new ProductType(['name' => 'Ghi']),
]);
评论
0赞
cytsunny
11/15/2023
需要一个数据库来调用,但我的情况没有数据库。save()
0赞
Win
11/28/2023
你有什么理由想在没有数据库的情况下测试你的代码吗?您想通过此测试实现什么?你能解释一下吗?
0赞
William Martins
11/15/2023
#4
代码波纹管工作正常。因此,您可以使用 setRelation。
<?php
namespace Tests\Unit;
use Illuminate\Database\Eloquent\Model;
use PHPUnit\Framework\TestCase;
class ProductType extends Model
{
public function products()
{
return $this->hasMany(Product::class, 'product_id');
}
}
class Product extends Model
{
public function productType()
{
return $this->belongsTo(ProductType::class, 'product_type_id');
}
public function theComplicatedFunctionBeingTested()
{
return $this->productType->name . " " . $this->name;
}
}
class Test extends TestCase
{
private $testProduct, $testProductType;
private function commonDataSetUp()
{
$this->testProductType = new ProductType;
$this->testProductType->product_type_id = 1;
$this->testProductType->name = "publication";
$this->testProduct = new Product;
$this->testProduct->name = "testing product";
$this->testProduct->setRelation('productType', $this->testProductType);
}
public function testComplicatedProductFunction()
{
$this->commonDataSetUp();
$result = $this->testProduct->theComplicatedFunctionBeingTested();
$this->assertEquals("publication testing product", $result);
}
}
评论
0赞
cytsunny
11/15/2023
我已经尝试了该函数,但如果不调用它就无法工作setRelation()
save()
0赞
William Martins
11/16/2023
我不明白。由于我提供的代码工作正常并且测试通过。您是否看到任何错误,或者您能否提供更多代码/上下文?
0赞
cytsunny
11/16/2023
我测试该方法的实际代码是不同的(因为它是我无法在此处公开粘贴的工作代码),但基本上代码在调用时仍在尝试在数据库中搜索,从而导致连接错误,因为没有用于测试的数据库设置。这意味着 setRelation 不是工作属性,因此模型需要在数据库中搜索产品所具有的 productType。$this->productType->name
0赞
William Martins
11/17/2023
您确定错误发生在这段代码上吗?我在操场上运行了它,它在没有数据库的情况下工作:laravelplayground.com/#/snippets/......
0赞
cytsunny
11/17/2023
是的,我敢肯定正是那条线导致了问题。我紧随其后添加了该行,它尝试访问数据库。我想可能的区别要么是因为我使用的是 Laravel 9,要么是在路由函数而不是 UnitTest 中调用了 playground 代码?dd($this->testProduct->productType
$this->commonDataSetUp()
评论