Bläddra i källkod

MafOrderController test, SparePartReservationService test

Alexander Musikhin 2 veckor sedan
förälder
incheckning
77db0a320f

+ 234 - 0
tests/Feature/MafOrderControllerTest.php

@@ -0,0 +1,234 @@
+<?php
+
+namespace Tests\Feature;
+
+use App\Models\MafOrder;
+use App\Models\Product;
+use App\Models\Role;
+use App\Models\User;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
+
+class MafOrderControllerTest extends TestCase
+{
+    use RefreshDatabase;
+
+    protected $seed = true;
+
+    private User $adminUser;
+    private User $managerUser;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $this->adminUser = User::factory()->create(['role' => Role::ADMIN]);
+        $this->managerUser = User::factory()->create(['role' => Role::MANAGER]);
+    }
+
+    // ==================== Authentication ====================
+
+    public function test_guest_cannot_access_maf_orders_index(): void
+    {
+        $response = $this->get(route('maf_order.index'));
+
+        $response->assertRedirect(route('login'));
+    }
+
+    public function test_authenticated_admin_can_access_maf_orders_index(): void
+    {
+        $response = $this->actingAs($this->adminUser)
+            ->get(route('maf_order.index'));
+
+        $response->assertStatus(200);
+        $response->assertViewIs('maf_orders.index');
+    }
+
+    public function test_manager_cannot_access_maf_orders_index(): void
+    {
+        $response = $this->actingAs($this->managerUser)
+            ->get(route('maf_order.index'));
+
+        $response->assertStatus(403);
+    }
+
+    // ==================== Index ====================
+
+    public function test_maf_orders_index_displays_orders(): void
+    {
+        MafOrder::factory()->create();
+
+        $response = $this->actingAs($this->adminUser)
+            ->get(route('maf_order.index'));
+
+        $response->assertStatus(200);
+    }
+
+    // ==================== Store (create) ====================
+
+    public function test_can_create_maf_order(): void
+    {
+        $product = Product::factory()->create();
+
+        $response = $this->actingAs($this->adminUser)
+            ->post(route('maf_order.store'), [
+                'product_id' => $product->id,
+                'quantity'   => 5,
+                'order_number' => 'MO-TEST-001',
+            ]);
+
+        $response->assertRedirect();
+        $this->assertDatabaseHas('maf_orders', [
+            'product_id'   => $product->id,
+            'quantity'     => 5,
+            'order_number' => 'MO-TEST-001',
+            'in_stock'     => 0,
+        ]);
+    }
+
+    public function test_store_maf_order_requires_product_id(): void
+    {
+        $response = $this->actingAs($this->adminUser)
+            ->post(route('maf_order.store'), [
+                'quantity' => 5,
+            ]);
+
+        $response->assertSessionHasErrors('product_id');
+    }
+
+    public function test_store_maf_order_requires_quantity(): void
+    {
+        $product = Product::factory()->create();
+
+        $response = $this->actingAs($this->adminUser)
+            ->post(route('maf_order.store'), [
+                'product_id' => $product->id,
+            ]);
+
+        $response->assertSessionHasErrors('quantity');
+    }
+
+    public function test_guest_cannot_create_maf_order(): void
+    {
+        $product = Product::factory()->create();
+
+        $response = $this->post(route('maf_order.store'), [
+            'product_id' => $product->id,
+            'quantity'   => 3,
+        ]);
+
+        $response->assertRedirect(route('login'));
+    }
+
+    // ==================== Show ====================
+
+    public function test_can_view_maf_order_details(): void
+    {
+        $mafOrder = MafOrder::factory()->create();
+
+        $response = $this->actingAs($this->adminUser)
+            ->get(route('maf_order.show', $mafOrder));
+
+        $response->assertStatus(200);
+        $response->assertViewIs('maf_orders.edit');
+    }
+
+    public function test_guest_cannot_view_maf_order_details(): void
+    {
+        $mafOrder = MafOrder::factory()->create();
+
+        $response = $this->get(route('maf_order.show', $mafOrder));
+
+        $response->assertRedirect(route('login'));
+    }
+
+    // ==================== Update ====================
+
+    public function test_can_update_maf_order(): void
+    {
+        $product = Product::factory()->create();
+        $mafOrder = MafOrder::factory()->create([
+            'product_id' => $product->id,
+            'quantity'   => 3,
+        ]);
+
+        $response = $this->actingAs($this->adminUser)
+            ->post(route('maf_order.update', $mafOrder), [
+                'product_id'   => $product->id,
+                'quantity'     => 10,
+                'order_number' => 'MO-UPDATED',
+            ]);
+
+        $response->assertRedirect();
+        $this->assertDatabaseHas('maf_orders', [
+            'id'       => $mafOrder->id,
+            'quantity' => 10,
+        ]);
+    }
+
+    public function test_guest_cannot_update_maf_order(): void
+    {
+        $product = Product::factory()->create();
+        $mafOrder = MafOrder::factory()->create(['product_id' => $product->id]);
+
+        $response = $this->post(route('maf_order.update', $mafOrder), [
+            'product_id' => $product->id,
+            'quantity'   => 10,
+        ]);
+
+        $response->assertRedirect(route('login'));
+    }
+
+    // ==================== Destroy ====================
+
+    public function test_can_delete_maf_order(): void
+    {
+        $mafOrder = MafOrder::factory()->create();
+        $mafOrderId = $mafOrder->id;
+
+        $response = $this->actingAs($this->adminUser)
+            ->delete(route('maf_order.delete', $mafOrder));
+
+        $response->assertRedirect();
+        $this->assertSoftDeleted('maf_orders', ['id' => $mafOrderId]);
+    }
+
+    public function test_guest_cannot_delete_maf_order(): void
+    {
+        $mafOrder = MafOrder::factory()->create();
+
+        $response = $this->delete(route('maf_order.delete', $mafOrder));
+
+        $response->assertRedirect(route('login'));
+    }
+
+    // ==================== SetInStock ====================
+
+    public function test_set_in_stock_updates_stock_and_status(): void
+    {
+        $mafOrder = MafOrder::factory()->create([
+            'quantity' => 8,
+            'in_stock' => 0,
+            'status'   => 'active',
+        ]);
+
+        $response = $this->actingAs($this->adminUser)
+            ->post(route('maf_order.set_in_stock', $mafOrder));
+
+        $response->assertRedirect(route('maf_order.show', $mafOrder));
+        $this->assertDatabaseHas('maf_orders', [
+            'id'       => $mafOrder->id,
+            'in_stock' => 8,
+            'status'   => 'на складе',
+        ]);
+    }
+
+    public function test_guest_cannot_set_in_stock(): void
+    {
+        $mafOrder = MafOrder::factory()->create(['quantity' => 5]);
+
+        $response = $this->post(route('maf_order.set_in_stock', $mafOrder));
+
+        $response->assertRedirect(route('login'));
+    }
+}

+ 172 - 0
tests/Unit/Services/SparePartReservationServiceMockTest.php

@@ -0,0 +1,172 @@
+<?php
+
+namespace Tests\Unit\Services;
+
+use App\Models\Reservation;
+use App\Models\Shortage;
+use App\Services\ReservationResult;
+use App\Services\ShortageService;
+use App\Services\SparePartReservationService;
+use Illuminate\Support\Collection;
+use Mockery;
+use Tests\TestCase;
+
+/**
+ * Unit-тесты SparePartReservationService с Mockery-моками без реальной БД.
+ *
+ * Тестирует:
+ * - Вычислительную логику ReservationResult (не требует БД)
+ * - Корректность инстанцирования сервиса с mock ShortageService
+ * - cancelReservation() с mock Reservation, где isActive() возвращает false
+ */
+class SparePartReservationServiceMockTest extends TestCase
+{
+    protected function tearDown(): void
+    {
+        Mockery::close();
+        parent::tearDown();
+    }
+
+    // ==================== ReservationResult: isFullyReserved ====================
+
+    public function test_reservation_result_is_fully_reserved_when_no_missing(): void
+    {
+        $shortage = Mockery::mock(Shortage::class);
+
+        $result = new ReservationResult(
+            reserved: 10,
+            missing: 0,
+            reservations: collect(),
+            shortage: null
+        );
+
+        $this->assertTrue($result->isFullyReserved());
+        $this->assertEquals(0, $result->missing);
+    }
+
+    // ==================== ReservationResult: hasShortage ====================
+
+    public function test_reservation_result_has_shortage_when_missing_exists(): void
+    {
+        $shortage = Mockery::mock(Shortage::class);
+
+        $result = new ReservationResult(
+            reserved: 3,
+            missing: 2,
+            reservations: collect(),
+            shortage: $shortage
+        );
+
+        $this->assertFalse($result->isFullyReserved());
+        $this->assertTrue($result->hasShortage());
+        $this->assertEquals(2, $result->missing);
+        $this->assertEquals(3, $result->reserved);
+    }
+
+    // ==================== ReservationResult: getTotalRequested ====================
+
+    public function test_reservation_result_get_total_requested_returns_sum(): void
+    {
+        $result = new ReservationResult(
+            reserved: 7,
+            missing: 3,
+            reservations: collect(),
+            shortage: null
+        );
+
+        $this->assertEquals(10, $result->getTotalRequested());
+    }
+
+    public function test_reservation_result_get_total_requested_when_fully_reserved(): void
+    {
+        $result = new ReservationResult(
+            reserved: 5,
+            missing: 0,
+            reservations: collect(),
+            shortage: null
+        );
+
+        $this->assertEquals(5, $result->getTotalRequested());
+    }
+
+    public function test_reservation_result_get_total_requested_when_nothing_reserved(): void
+    {
+        $result = new ReservationResult(
+            reserved: 0,
+            missing: 8,
+            reservations: collect(),
+            shortage: null
+        );
+
+        $this->assertEquals(8, $result->getTotalRequested());
+    }
+
+    // ==================== Service instantiation ====================
+
+    public function test_service_accepts_shortage_service_dependency(): void
+    {
+        $shortageService = Mockery::mock(ShortageService::class);
+
+        $service = new SparePartReservationService($shortageService);
+
+        $this->assertInstanceOf(SparePartReservationService::class, $service);
+    }
+
+    public function test_service_can_be_instantiated_with_real_shortage_service(): void
+    {
+        $shortageService = new ShortageService();
+        $service = new SparePartReservationService($shortageService);
+
+        $this->assertInstanceOf(SparePartReservationService::class, $service);
+    }
+
+    // ==================== cancelReservation: non-active reservation ====================
+
+    public function test_cancel_reservation_returns_false_for_non_active(): void
+    {
+        $shortageService = Mockery::mock(ShortageService::class);
+        $service = new SparePartReservationService($shortageService);
+
+        $reservation = Mockery::mock(Reservation::class);
+        $reservation->shouldReceive('isActive')->once()->andReturn(false);
+
+        $result = $service->cancelReservation($reservation);
+
+        $this->assertFalse($result);
+    }
+
+    // ==================== ReservationResult: reservations collection ====================
+
+    public function test_reservation_result_holds_reservations_collection(): void
+    {
+        $reservations = collect([
+            Mockery::mock(Reservation::class),
+            Mockery::mock(Reservation::class),
+        ]);
+
+        $result = new ReservationResult(
+            reserved: 2,
+            missing: 0,
+            reservations: $reservations,
+            shortage: null
+        );
+
+        $this->assertInstanceOf(Collection::class, $result->reservations);
+        $this->assertCount(2, $result->reservations);
+        $this->assertTrue($result->isFullyReserved());
+        $this->assertFalse($result->hasShortage());
+    }
+
+    public function test_reservation_result_has_no_shortage_when_shortage_is_null(): void
+    {
+        $result = new ReservationResult(
+            reserved: 5,
+            missing: 0,
+            reservations: collect(),
+            shortage: null
+        );
+
+        $this->assertFalse($result->hasShortage());
+        $this->assertNull($result->shortage);
+    }
+}