|
@@ -0,0 +1,256 @@
|
|
|
|
|
+# Тестовое покрытие проекта Stroyprofit CRM
|
|
|
|
|
+
|
|
|
|
|
+## Текущее состояние
|
|
|
|
|
+
|
|
|
|
|
+### Инфраструктура тестирования
|
|
|
|
|
+
|
|
|
|
|
+- **Фреймворк:** PHPUnit 11
|
|
|
|
|
+- **Доп. зависимости:** Mockery (подключён, но не используется), Faker (используется в фабриках)
|
|
|
|
|
+- **БД в тестах:** реальная MySQL (SQLite закомментирован в `phpunit.xml`)
|
|
|
|
|
+- **Сброс БД:** `RefreshDatabase` + `$seed = true` в каждом тест-классе
|
|
|
|
|
+- **Моки:** не применяются — все зависимости реальные (интеграционный стиль)
|
|
|
|
|
+
|
|
|
|
|
+### Статистика
|
|
|
|
|
+
|
|
|
|
|
+| Категория | Всего файлов | Покрыто | Покрытие |
|
|
|
|
|
+|------------------|-------------|---------|----------|
|
|
|
|
|
+| Тест-файлов | 29 | — | — |
|
|
|
|
|
+| Тест-методов | ~302 | — | — |
|
|
|
|
|
+| Модели | 34 | 5 | ~15% |
|
|
|
|
|
+| Сервисы | 28 | 13 | ~46% |
|
|
|
|
|
+| Jobs | 21 | 0 | 0% |
|
|
|
|
|
+| Контроллеры | 30 | 4 | ~13% |
|
|
|
|
|
+| Form Requests | 22 | 0 | 0% |
|
|
|
|
|
+| Helpers | 5 | 3 | 60% |
|
|
|
|
|
+| Observers | 1 | 1 | 100% |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Что покрыто тестами
|
|
|
|
|
+
|
|
|
|
|
+### Unit — Helpers
|
|
|
|
|
+- `CountHelper` — числительные (единицы/2-4/5+)
|
|
|
|
|
+- `DateHelper` — конвертация дат (Excel, ISO, человеческий формат)
|
|
|
|
|
+- `Price` — форматирование цен с символом ₽
|
|
|
|
|
+
|
|
|
|
|
+### Unit — Models
|
|
|
|
|
+- `Order` — константы статусов, атрибуты, связи, soft delete
|
|
|
|
|
+- `Reclamation` — константы статусов, связи, activeReservations, openShortages
|
|
|
|
|
+- `InventoryMovement` — константы типов, акцессоры, связи, скоупы, касты
|
|
|
|
|
+- `Shortage` — статусы, акцессоры, связи, скоупы, методы addReserved/recalculate
|
|
|
|
|
+- `SparePartOrder` — статусы, reserved_qty, free_qty, canReserve, скоупы
|
|
|
|
|
+- `SparePart` — цены в копейках, складские остатки, резервы, minimum stock
|
|
|
|
|
+
|
|
|
|
|
+### Unit — Services
|
|
|
|
|
+- `FileService` — сохранение файлов (Unicode, спецсимволы, дубликаты)
|
|
|
|
|
+- `GenerateDocumentsService` — генерация ZIP-архивов, монтаж/сдача/рекламация (частично через markTestSkipped)
|
|
|
|
|
+- `ImportOrdersService` — импорт заказов из Excel
|
|
|
|
|
+- `ShortageService` — FIFO, processPartOrderReceipt, calculateOrderQuantity, getCriticalShortages
|
|
|
|
|
+- `SparePartInventoryService` — getStockInfo, getInventorySummary, getBelowMinStock
|
|
|
|
|
+- `SparePartIssueService` — issueReservation, issueForReclamation, directIssue, correctInventory
|
|
|
|
|
+- `SparePartReservationService` — reserve, cancelForReclamation, adjustReservation
|
|
|
|
|
+- `Export/ExportAreasService` — экспорт районов в XLSX
|
|
|
|
|
+- `Export/ExportDistrictsService` — экспорт округов в XLSX
|
|
|
|
|
+- `Import/ImportAreasService` — импорт районов (создание, обновление, восстановление)
|
|
|
|
|
+- `Import/ImportDistrictsService` — импорт округов
|
|
|
|
|
+- `Import/ImportMafOrdersService` — импорт MAF-заказов
|
|
|
|
|
+- `Import/ImportSparePartOrdersService` — импорт заказов запчастей
|
|
|
|
|
+
|
|
|
|
|
+### Unit — Observers
|
|
|
|
|
+- `SparePartOrderObserver` — автопокрытие shortages при создании/обновлении заказа
|
|
|
|
|
+
|
|
|
|
|
+### Feature
|
|
|
|
|
+- `AdminAreaController` — CRUD + import/export (16 тестов)
|
|
|
|
|
+- `AdminDistrictController` — CRUD + import/export (15 тестов)
|
|
|
|
|
+- `OrderController` — CRUD, MAF-операции, фото, документы, генерация, экспорт (22 теста)
|
|
|
|
|
+- `ReclamationController` — CRUD, файлы, запчасти, детали, генерация (22 теста)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Доработки
|
|
|
|
|
+
|
|
|
|
|
+### Приоритет 1 — Критически важно
|
|
|
|
|
+
|
|
|
|
|
+#### 1.1 Перевести БД на SQLite in-memory для тестов
|
|
|
|
|
+**Файл:** `phpunit.xml`
|
|
|
|
|
+
|
|
|
|
|
+Раскомментировать строки:
|
|
|
|
|
+```xml
|
|
|
|
|
+<env name="DB_CONNECTION" value="sqlite"/>
|
|
|
|
|
+<env name="DB_DATABASE" value=":memory:"/>
|
|
|
|
|
+```
|
|
|
|
|
+Текущая конфигурация требует запущенную MySQL, что делает запуск тестов в CI и на чистой машине невозможным без дополнительной настройки. Нужно убедиться, что все миграции совместимы с SQLite (убрать специфичные для MySQL типы: `json` → `text`, `enum` → `string`, fulltext-индексы).
|
|
|
|
|
+
|
|
|
|
|
+#### 1.2 Покрыть Jobs тестами (0% покрытие)
|
|
|
|
|
+Все 21 джоб не имеют тестов. Минимально необходимо покрыть:
|
|
|
|
|
+
|
|
|
|
|
+| Job | Что тестировать |
|
|
|
|
|
+|-----|----------------|
|
|
|
|
|
+| `ExportOrdersJob` | диспетчеризация, создание файла, статус Import |
|
|
|
|
|
+| `ExportMafJob` | аналогично |
|
|
|
|
|
+| `ExportReclamationsJob` | аналогично |
|
|
|
|
|
+| `ExportScheduleJob` | аналогично |
|
|
|
|
|
+| `GenerateFilesPack` | создание ZIP, корректность содержимого |
|
|
|
|
|
+| `GenerateInstallationPack` | аналогично |
|
|
|
|
|
+| `GenerateHandoverPack` | аналогично |
|
|
|
|
|
+| `ImportJob` | обработка файла, ошибки валидации |
|
|
|
|
|
+| `NotifyManagerNewOrderJob` | отправка уведомления (мок FCM) |
|
|
|
|
|
+| `NotifyManagerChangeStatusJob` | аналогично |
|
|
|
|
|
+
|
|
|
|
|
+**Рекомендация:** использовать `Queue::fake()` + `Bus::fake()` для проверки диспетчеризации без реального выполнения.
|
|
|
|
|
+
|
|
|
|
|
+#### 1.3 Подключить Mockery и использовать моки
|
|
|
|
|
+Сейчас все тесты сервисов — интеграционные (реальная БД). Это медленно и хрупко. Нужно добавить unit-тесты с моками для изоляции зависимостей:
|
|
|
|
|
+
|
|
|
|
|
+```php
|
|
|
|
|
+// Пример: мокировать репозиторий в SparePartReservationService
|
|
|
|
|
+$sparePart = Mockery::mock(SparePart::class);
|
|
|
|
|
+$sparePart->shouldReceive('lockForUpdate')->andReturnSelf();
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Приоритет 2 — Важно
|
|
|
|
|
+
|
|
|
|
|
+#### 2.1 Покрыть контроллеры Feature-тестами
|
|
|
|
|
+Не покрытые контроллеры с высоким бизнес-приоритетом:
|
|
|
|
|
+
|
|
|
|
|
+| Контроллер | Что тестировать |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `MafOrderController` | CRUD, статусы, документы |
|
|
|
|
|
+| `SparePartController` | CRUD, цены, остатки |
|
|
|
|
|
+| `SparePartOrderController` | создание, статусы, отгрузки |
|
|
|
|
|
+| `SparePartReservationController` | резервирование, отмена |
|
|
|
|
|
+| `SparePartInventoryController` | инвентаризация |
|
|
|
|
|
+| `ContractController` | CRUD, загрузка файлов |
|
|
|
|
|
+| `ScheduleController` | создание расписания из заказа/рекламации |
|
|
|
|
|
+| `ImportController` | загрузка файла, диспетчеризация джоба |
|
|
|
|
|
+| `ReportController` | генерация отчётов, фильтрация |
|
|
|
|
|
+| `ProductController` / `ProductSKUController` | CRUD каталога |
|
|
|
|
|
+| `UserController` | создание, редактирование пользователей |
|
|
|
|
|
+
|
|
|
|
|
+Минимальный набор тестов для каждого контроллера:
|
|
|
|
|
+- Неаутентифицированный запрос → редирект на логин
|
|
|
|
|
+- Успешный запрос → корректный ответ (200/redirect)
|
|
|
|
|
+- Невалидные данные → 422 / ошибки валидации
|
|
|
|
|
+- Авторизация (роли) — если применима
|
|
|
|
|
+
|
|
|
|
|
+#### 2.2 Покрыть Form Requests тестами
|
|
|
|
|
+22 Request-класса не имеют изолированных тестов. Добавить тесты валидации:
|
|
|
|
|
+
|
|
|
|
|
+```php
|
|
|
|
|
+// tests/Unit/Requests/StoreOrderRequestTest.php
|
|
|
|
|
+public function test_required_fields(): void
|
|
|
|
|
+{
|
|
|
|
|
+ $request = new StoreOrderRequest();
|
|
|
|
|
+ $validator = Validator::make([], $request->rules());
|
|
|
|
|
+ $this->assertTrue($validator->fails());
|
|
|
|
|
+ $this->assertArrayHasKey('client_name', $validator->errors()->toArray());
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Приоритетные Request-классы:
|
|
|
|
|
+- `Order/StoreOrderRequest` — основная форма заказа
|
|
|
|
|
+- `StoreMafOrderRequest` — форма MAF
|
|
|
|
|
+- `StoreReclamationRequest` / `StoreReclamationDetailsRequest`
|
|
|
|
|
+- `StoreSparePartOrderRequest` / `ShipSparePartOrderRequest`
|
|
|
|
|
+- `StoreContractRequest`
|
|
|
|
|
+
|
|
|
|
|
+#### 2.3 Покрыть непокрытые сервисы
|
|
|
|
|
+
|
|
|
|
|
+| Сервис | Что тестировать |
|
|
|
|
|
+|--------|----------------|
|
|
|
|
|
+| `ExportOrdersService` | формирование XLSX, корректность данных |
|
|
|
|
|
+| `ExportMafService` | аналогично |
|
|
|
|
|
+| `ExportReclamationsService` | аналогично |
|
|
|
|
|
+| `ExportScheduleService` | аналогично |
|
|
|
|
|
+| `ExportSparePartsService` | аналогично |
|
|
|
|
|
+| `ImportReclamationsService` | импорт, маппинг, ошибки |
|
|
|
|
|
+| `ImportMafsService` | аналогично |
|
|
|
|
|
+| `ImportCatalogService` | создание/обновление товаров |
|
|
|
|
|
+| `Import/ImportSparePartsService` | аналогично |
|
|
|
|
|
+| `Import/ImportYearDataService` | аналогично |
|
|
|
|
|
+| `PdfConverterClient` | HTTP-запрос к PDF-сервису (мок HTTP-клиента) |
|
|
|
|
|
+| `Export/ExportYearDataService` | аналогично |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Приоритет 3 — Желательно
|
|
|
|
|
+
|
|
|
|
|
+#### 3.1 Покрыть непокрытые модели
|
|
|
|
|
+Модели без тестов (нет отдельных тест-файлов):
|
|
|
|
|
+
|
|
|
|
|
+- `MafOrder` — статусы, связи, атрибуты
|
|
|
|
|
+- `Product` / `ProductSKU` — связи, SKU-логика
|
|
|
|
|
+- `Contract` — связи, загрузка файлов
|
|
|
|
|
+- `Schedule` — связи с Order/Reclamation, статусы
|
|
|
|
|
+- `Reservation` — связи, статусы, количество
|
|
|
|
|
+- `SparePartOrderShipment` — списание резервов
|
|
|
|
|
+- `Dictionary/Area` / `Dictionary/District` — soft delete, связи
|
|
|
|
|
+- Database Views (`OrderView`, `MafOrdersView` и т.д.) — корректность агрегации
|
|
|
|
|
+
|
|
|
|
|
+#### 3.2 Покрыть непокрытые Helpers
|
|
|
|
|
+
|
|
|
|
|
+- `ExcelHelper` — форматирование ячеек, типы данных
|
|
|
|
|
+- `roles.php` — проверка наличия/наименования ролей
|
|
|
|
|
+
|
|
|
|
|
+#### 3.3 Добавить тесты для Auth-контроллеров
|
|
|
|
|
+Покрыть базовые сценарии аутентификации:
|
|
|
|
|
+- Успешный логин
|
|
|
|
|
+- Логин с неверным паролем
|
|
|
|
|
+- Выход из системы
|
|
|
|
|
+- Сброс пароля (если используется)
|
|
|
|
|
+
|
|
|
|
|
+#### 3.4 Добавить тесты политик авторизации (Policies/Gates)
|
|
|
|
|
+Если в проекте есть ролевая модель (файл `roles.php`, `Role` модель) — добавить тесты:
|
|
|
|
|
+- Доступ к admin-контроллерам только для admin-роли
|
|
|
|
|
+- Запрет доступа для пользователей без нужной роли
|
|
|
|
|
+
|
|
|
|
|
+#### 3.5 Настроить покрытие кода (Coverage)
|
|
|
|
|
+Добавить генерацию HTML-отчёта покрытия:
|
|
|
|
|
+
|
|
|
|
|
+```xml
|
|
|
|
|
+<!-- phpunit.xml -->
|
|
|
|
|
+<coverage>
|
|
|
|
|
+ <report>
|
|
|
|
|
+ <html outputDirectory="coverage"/>
|
|
|
|
|
+ <clover outputFile="coverage.xml"/>
|
|
|
|
|
+ </report>
|
|
|
|
|
+</coverage>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Требуется Xdebug или PCOV. Добавить в `Makefile`:
|
|
|
|
|
+```bash
|
|
|
|
|
+make test-coverage # php artisan test --coverage
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Технические проблемы
|
|
|
|
|
+
|
|
|
|
|
+### Тесты зависят от наличия Excel-шаблонов
|
|
|
|
|
+`GenerateDocumentsServiceTest` использует `markTestSkipped()` если шаблоны отсутствуют в `/templates/`. Нужно:
|
|
|
|
|
+- Добавить тестовые шаблоны в `tests/fixtures/templates/`
|
|
|
|
|
+- Или сделать шаблоны доступными в CI через переменную окружения
|
|
|
|
|
+
|
|
|
|
|
+### Фикстура `tests/fixtures/test_orders_import.xlsx`
|
|
|
|
|
+`ImportOrdersServiceTest` требует реальный xlsx-файл. Убедиться что файл находится в git и содержит актуальные данные.
|
|
|
|
|
+
|
|
|
|
|
+### Нет изоляции тестов сервисов
|
|
|
|
|
+Все Unit-тесты сервисов реально обращаются к БД — это интеграционные тесты. Нужно:
|
|
|
|
|
+- Переименовать директорию `tests/Unit/Services/` → `tests/Integration/Services/`
|
|
|
|
|
+- Или создать настоящие Unit-тесты с моками зависимостей
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Рекомендуемый порядок выполнения доработок
|
|
|
|
|
+
|
|
|
|
|
+1. Настроить SQLite in-memory в `phpunit.xml` (быстрый прогресс без кода)
|
|
|
|
|
+2. Покрыть `MafOrderController` Feature-тестами (высокий бизнес-приоритет)
|
|
|
|
|
+3. Покрыть `SparePartController` + `SparePartOrderController` Feature-тестами
|
|
|
|
|
+4. Добавить тесты для `ExportOrdersService` и других экспорт-сервисов
|
|
|
|
|
+5. Покрыть Form Requests тестами (быстро, высокая ценность)
|
|
|
|
|
+6. Добавить тесты для Jobs с `Queue::fake()`
|
|
|
|
|
+7. Настроить Coverage-отчёт
|
|
|
|
|
+8. Добавить тесты Auth-контроллеров
|
|
|
|
|
+9. Покрыть оставшиеся модели и контроллеры
|