Files
sam-api/tests/Unit/Production/DynamicBomEntryTest.php
권혁성 5a3d6c2243 feat(WEB): 절곡 자재투입 LOT 매핑 파이프라인 구현
- PrefixResolver: 제품코드×마감재질→LOT prefix 결정 + BD-XX-NN 코드 생성
- DynamicBomEntry DTO: dynamic_bom JSON 항목 타입 안전 관리
- BendingInfoBuilder 확장: build() 리턴 변경 + buildDynamicBomForItem() 추가
- OrderService: 작업지시 생성 시 per-item dynamic_bom 자동 저장
- WorkOrderService.getMaterials(): dynamic_bom 우선 체크 + N+1 배치 최적화
- WorkOrderService.registerMaterialInput(): work_order_item_id 분기 라우팅 통일
- 단위 테스트 58개 + 통합 테스트 6개 (64 tests / 293 assertions)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 04:19:47 +09:00

174 lines
6.5 KiB
PHP

<?php
namespace Tests\Unit\Production;
use App\DTOs\Production\DynamicBomEntry;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
class DynamicBomEntryTest extends TestCase
{
private function validData(): array
{
return [
'child_item_id' => 15812,
'child_item_code' => 'BD-RS-43',
'lot_prefix' => 'RS',
'part_type' => '마감재',
'category' => 'guideRail',
'material_type' => 'SUS',
'length_mm' => 4300,
'qty' => 2,
];
}
// ─────────────────────────────────────────────────
// fromArray + toArray 라운드트립
// ─────────────────────────────────────────────────
public function test_from_array_creates_dto(): void
{
$entry = DynamicBomEntry::fromArray($this->validData());
$this->assertEquals(15812, $entry->child_item_id);
$this->assertEquals('BD-RS-43', $entry->child_item_code);
$this->assertEquals('RS', $entry->lot_prefix);
$this->assertEquals('마감재', $entry->part_type);
$this->assertEquals('guideRail', $entry->category);
$this->assertEquals('SUS', $entry->material_type);
$this->assertEquals(4300, $entry->length_mm);
$this->assertEquals(2, $entry->qty);
}
public function test_to_array_round_trip(): void
{
$data = $this->validData();
$entry = DynamicBomEntry::fromArray($data);
$this->assertEquals($data, $entry->toArray());
}
public function test_to_array_list(): void
{
$entries = [
DynamicBomEntry::fromArray($this->validData()),
DynamicBomEntry::fromArray(array_merge($this->validData(), [
'child_item_id' => 15813,
'child_item_code' => 'BD-RM-43',
'lot_prefix' => 'RM',
'part_type' => '본체',
])),
];
$list = DynamicBomEntry::toArrayList($entries);
$this->assertCount(2, $list);
$this->assertEquals('BD-RS-43', $list[0]['child_item_code']);
$this->assertEquals('BD-RM-43', $list[1]['child_item_code']);
}
// ─────────────────────────────────────────────────
// 유효한 카테고리
// ─────────────────────────────────────────────────
/**
* @dataProvider validCategoryProvider
*/
public function test_valid_categories(string $category): void
{
$data = array_merge($this->validData(), ['category' => $category]);
$entry = DynamicBomEntry::fromArray($data);
$this->assertEquals($category, $entry->category);
}
public static function validCategoryProvider(): array
{
return [
'guideRail' => ['guideRail'],
'bottomBar' => ['bottomBar'],
'shutterBox' => ['shutterBox'],
'smokeBarrier' => ['smokeBarrier'],
];
}
// ─────────────────────────────────────────────────
// 필수 필드 누락 검증
// ─────────────────────────────────────────────────
/**
* @dataProvider requiredFieldProvider
*/
public function test_missing_required_field_throws(string $field): void
{
$data = $this->validData();
unset($data[$field]);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("'{$field}' is required");
DynamicBomEntry::fromArray($data);
}
public static function requiredFieldProvider(): array
{
return [
'child_item_id' => ['child_item_id'],
'child_item_code' => ['child_item_code'],
'lot_prefix' => ['lot_prefix'],
'part_type' => ['part_type'],
'category' => ['category'],
'material_type' => ['material_type'],
'length_mm' => ['length_mm'],
'qty' => ['qty'],
];
}
// ─────────────────────────────────────────────────
// 값 제약 검증
// ─────────────────────────────────────────────────
public function test_invalid_child_item_id_throws(): void
{
$data = array_merge($this->validData(), ['child_item_id' => 0]);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('child_item_id must be positive');
DynamicBomEntry::fromArray($data);
}
public function test_invalid_category_throws(): void
{
$data = array_merge($this->validData(), ['category' => 'invalidCategory']);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('category must be one of');
DynamicBomEntry::fromArray($data);
}
public function test_zero_qty_throws(): void
{
$data = array_merge($this->validData(), ['qty' => 0]);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('qty must be positive');
DynamicBomEntry::fromArray($data);
}
public function test_negative_qty_throws(): void
{
$data = array_merge($this->validData(), ['qty' => -1]);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('qty must be positive');
DynamicBomEntry::fromArray($data);
}
// ─────────────────────────────────────────────────
// float qty 허용
// ─────────────────────────────────────────────────
public function test_float_qty_allowed(): void
{
$data = array_merge($this->validData(), ['qty' => 1.5]);
$entry = DynamicBomEntry::fromArray($data);
$this->assertEquals(1.5, $entry->qty);
}
}