food-market/tests/food-market.UnitTests/RetailPaymentValidatorTests.cs
nns f3d517f257 test(unit): xUnit-проект food-market.UnitTests, 23 теста (P1-20)
Чистая логика вынесена в Application для тестируемости и используется контроллерами:
- MovingAverageCost.Compute (скользящее среднее себестоимости) ← SuppliesController.Post
- RetailPaymentValidator.IsSufficient (достаточность оплаты) ← RetailSalesController.Post

Тесты:
- MovingAverageCost: первая приёмка, средневзвешенное, округление до 4 знаков, totalQty=0.
- RetailPaymentValidator: ровно/переплата/недоплата, округление до 2 знаков.
- StockService.ApplyMovement (SQLite in-memory): материализация Stock+движение,
  инкремент, отрицательное списание, throw без tenant.
- Мультитенантный query-filter AppDbContext: tenant видит своё; чужой не видит;
  SuperAdmin без override — всё; с override — только выбранную оргу.

Все 23 зелёные. EF8 SQLite поддерживает ToJson (EmployeeRole.Permissions).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 03:01:56 +05:00

35 lines
1.7 KiB
C#

using FluentAssertions;
using foodmarket.Application.Sales;
using Xunit;
namespace foodmarket.UnitTests;
/// <summary>Достаточность оплаты розничного чека (логика RetailSalesController.Post).</summary>
public class RetailPaymentValidatorTests
{
[Theory]
[InlineData(1000, 0, 1000)] // ровно наличными
[InlineData(0, 1000, 1000)] // ровно картой
[InlineData(600, 400, 1000)] // смешанная оплата, ровно
[InlineData(1500, 0, 1000)] // переплата наличными (сдача) — ок
[InlineData(700, 700, 1000)] // переплата смешанная — ок
public void Sufficient_payment_passes(decimal cash, decimal card, decimal total)
=> RetailPaymentValidator.IsSufficient(cash, card, total).Should().BeTrue();
[Theory]
[InlineData(999, 0, 1000)] // недоплата наличными
[InlineData(0, 0, 1000)] // не оплачено вовсе
[InlineData(400, 400, 1000)] // смешанная недоплата
public void Insufficient_payment_fails(decimal cash, decimal card, decimal total)
=> RetailPaymentValidator.IsSufficient(cash, card, total).Should().BeFalse();
[Fact]
public void Rounds_to_two_decimals_before_comparing()
{
// 999.999 округляется до 1000.00 ≥ 1000 → ок (защита от float-дрейфа)
RetailPaymentValidator.IsSufficient(999.999m, 0m, 1000m).Should().BeTrue();
// 999.994 → 999.99 < 1000 → недоплата
RetailPaymentValidator.IsSufficient(999.994m, 0m, 1000m).Should().BeFalse();
}
}