Цель: подтвердить корректность расчётов, статусов, целостность данных (JSON), устойчивость к ошибочному вводу и соответствие ТЗ.
Объекты тестирования: TariffCalculator, RentalService, DataStorage, модели (InventoryItem, Rental), консольный UI.
| Вид тестов | Покрытие |
|---|---|
| Модульные | расчёт тарифов, изменение статусов, закрытие аренды |
| Интеграционные | цепочка: UI → Service → Storage |
| Границы/классы | интервалы времени (rounding), эквивалентные классы ввода |
| Негативные | ошибки/исключения (недоступный инвентарь, битый JSON) |
| Регрессионные | повторный прогон после исправлений |
| Простейшая производительность | отклик на наборе до 1000 записей |
flowchart LR
Found[Найден дефект] --> Logged[Заведён BUG]
Logged --> Dev[Исправление]
Dev --> Test[Проверка/регресс]
Test -->|OK| Closed[Закрыт]
Test -->|Fail| Reopen[Переоткрыт] --> Dev
end > start → расчёт > 0.end == start или end < start → сумма = 0 (или исключение по политике).available, rented, maintenance.hour, day, package.package — фикс.hour при правиле ceil_30min| Минуты | Ожидаемый биллинговый час |
|---|---|
| 0–29 | hours |
| 30–59 | hours + 1 |
| Минимум 1 час независимо от длительности > 0 мин. | |
day| Длительность | Ожидаемые дни к оплате |
|---|---|
| 1–24 ч | 1 |
| 24 ч + 1 мин | 2 |
| N суток ровно | N |
| ID | Что тестируем | Входные данные | Ожидаемый результат |
|---|---|---|---|
| TC-CALC-01 | Часовой: 15 мин | start=10:00 end=10:15 rate=300 | 1 * 300 = 300 |
| TC-CALC-02 | Часовой: 1ч29м | start=10:00 end=11:29 rate=300 | 1 * 300 = 300 |
| TC-CALC-03 | Часовой: 1ч30м | start=10:00 end=11:30 rate=300 | 2 * 300 = 600 |
| TC-CALC-04 | Часовой: 1ч35м | start=10:00 end=11:35 rate=300 | 2 * 300 = 600 |
| TC-CALC-05 | Переход суток | start=23:30 end=00:20 rate=300 | 1 * 300 = 300 |
| TC-CALC-06 | Суточный: 25 ч | mode=day rate=1200 | 2 * 1200 = 2400 |
| TC-STATUS-01 | Открытие аренды | item.status=available | rental open, item=rented |
| TC-STATUS-02 | Двойная выдача | item.status=rented | исключение «недоступна для выдачи» |
| TC-RENT-01 | Закрытие аренды | open → close (1ч35м) | total = 600, item=available |
| TC-DATA-01 | JSON запись | SaveAll() | файлы обновлены, валидный JSON |
| TC-NEG-01 | Неверный статус | ChangeStatus("bad") | исключение OutOfRange |
| TC-NEG-02 | end < start | Calculate | сумма 0 (или исключение по политике) |
| TC-PERF-01 | 1000 записей | операции поиска | отклик ≤ 1 c (локально) |
rate = 300)| start | end | Минут сумм. | Биллинговые часы | Ожид. сумма |
|---|---|---|---|---|
| 10:00 | 10:15 | 15 | 1 | 300 |
| 10:00 | 10:59 | 59 | 1 | 300 |
| 10:00 | 11:00 | 60 | 1 | 300 |
| 10:00 | 11:30 | 90 | 2 | 600 |
| 10:00 | 11:35 | 95 | 2 | 600 |
rate = 1200)| Длительность | Ожид. дни | Сумма |
|---|---|---|
| 12 ч | 1 | 1200 |
| 24 ч | 1 | 1200 |
| 25 ч | 2 | 2400 |
Если потребуется, можно вынести в отдельный проект RentalApp.Tests и подключить NUnit.
// Install-Package NUnit
// Install-Package NUnit3TestAdapter
// Install-Package Microsoft.NET.Test.Sdk
using NUnit.Framework;
using RentalApp.Services;
using RentalApp.Domain;
[TestFixture]
public class TariffCalculatorTests
{
[Test]
public void Hour_1h30m_RoundsUp()
{
var t = new Tariff { Mode = "hour", Rate = 300, RoundRule = "ceil_30min" };
var calc = new TariffCalculator();
var sum = calc.Calculate(t, new DateTime(2025,1,1,10,0,0), new DateTime(2025,1,1,11,30,0));
Assert.AreEqual(600m, sum);
}
[Test]
public void Day_25h_TwoDays()
{
var t = new Tariff { Mode = "day", Rate = 1200 };
var calc = new TariffCalculator();
var sum = calc.Calculate(t, new DateTime(2025,1,1,10,0,0), new DateTime(2025,1,2,11,0,0));
Assert.AreEqual(2400m, sum);
}
}
| Сценарий | Действие | Ожидаемый результат |
|---|---|---|
| Пустые файлы данных | LoadAll() | списки инициализируются пустыми, приложение не падает |
| Отсутствует каталог data | запуск | каталог создаётся, файлы появляются при SaveAll() |
| Повреждённый JSON | LoadAll() | информативная ошибка в UI, предложение восстановить/пересоздать |
| Попытка закрыть закрытую аренду | CloseRental() | исключение «уже закрыт» |
| Выдача единицы на ТО | status=maintenance | отказ в операции |
| ID | Версия | Описание дефекта | Шаги воспроизведения | Факт. результат | Ожид. результат | Статус | Исправление |
|---|---|---|---|---|---|---|---|
| BUG-001 | v1.0 | Округление 1ч30м даёт 300 | start=10:00 end=11:30 | 300 | 600 | Fixed | исправлен расчёт minutes >= 30 |
| BUG-002 | v1.0 | Выдача предмета со статусом maintenance | OpenRental на item=maintenance | аренда создана | отказ | Fixed | проверка статуса в OpenRental |
| BUG-003 | v1.0 | Повреждённый JSON падает без сообщения | Запуск с битым items.json | исключение в консоли | понятное сообщение | Fixed | try/catch в Load, текст в UI |
Console.WriteLine): открытие/закрытие аренды, пути файлов, размеры коллекций.