diff --git a/README.md b/README.md new file mode 100644 index 0000000..fee0b79 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +\# Вариативная часть. Задание 5: тестирование программных модулей + + + +Проект ShoeStore.Logic содержит класс ProductCalculator (Приложение 4), проект ShoeStore.Tests - модульные тесты MSTest. + + + +\## Протокол тестирования + + + +Фреймворк модульного тестирования: MSTest (.NET 8). + + + +Порядок запуска тестов: + +1\. Открыть решение в Visual Studio 2022. + +2\. Меню «Тест» -> «Обозреватель тестов». + +3\. Нажать «Запустить все тесты в представлении». + + + +Запуск из командной строки (в папке решения): dotnet test + + + +| № | Проверяемый случай | Входные данные | Ожидаемый результат | Фактический результат | Статус | + +|---|---|---|---|---|---| + +| 1 | Заказов в предыдущем месяце нет | Цена 2000; заказов нет; дата расчета 15.06.2027 | 1500 | 1500 | Пройден | + +| 2 | Есть заказ в предыдущем месяце | Цена 2000; заказ 10.05.2027; дата расчета 15.06.2027 | 2000 | 2000 | Пройден | + +| 3 | Граничное значение количества | Количество пар: 5 | мало | мало | Пройден | + +| 4 | Количество больше порогового | Количество пар: 6 | много | много | Пройден | + + + diff --git a/ShoeStore.Logic.sln b/ShoeStore.Logic.sln new file mode 100644 index 0000000..efc8fc6 --- /dev/null +++ b/ShoeStore.Logic.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.37216.2 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShoeStore.Logic", "ShoeStore.Logic\ShoeStore.Logic.csproj", "{243ECAB7-9F51-4608-84B0-48DC7E3C5C3C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShoeStore.Tests", "ShoeStore.Tests\ShoeStore.Tests.csproj", "{FED8B0FF-E33E-493C-A134-43F3D05BD6CB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {243ECAB7-9F51-4608-84B0-48DC7E3C5C3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {243ECAB7-9F51-4608-84B0-48DC7E3C5C3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {243ECAB7-9F51-4608-84B0-48DC7E3C5C3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {243ECAB7-9F51-4608-84B0-48DC7E3C5C3C}.Release|Any CPU.Build.0 = Release|Any CPU + {FED8B0FF-E33E-493C-A134-43F3D05BD6CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FED8B0FF-E33E-493C-A134-43F3D05BD6CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FED8B0FF-E33E-493C-A134-43F3D05BD6CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FED8B0FF-E33E-493C-A134-43F3D05BD6CB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8E737E58-B5E1-47A9-8604-274B239853FC} + EndGlobalSection +EndGlobal diff --git a/ShoeStore.Logic/ProductCalculator.cs b/ShoeStore.Logic/ProductCalculator.cs new file mode 100644 index 0000000..795620d --- /dev/null +++ b/ShoeStore.Logic/ProductCalculator.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ShoeStore.Logic +{ + /// + /// Расчет показателей товара для каталога. + /// + public static class ProductCalculator + { + public const decimal DiscountPercent = 25m; + public const int ManyQuantityThreshold = 5; + + /// + /// Возвращает цену товара с учетом скидки. + /// Скидка 25% предоставляется, если в предыдущем календарном месяце + /// (относительно даты расчета) по товару не было заказов. + /// + /// Цена товара в рублях. + /// Даты заказов товара (может быть пустым). + /// Дата расчета. + public static decimal CalculateDiscountedPrice(decimal price, IEnumerable orderDates, DateTime calculationDate) + { + if (price < 0) + { + throw new ArgumentOutOfRangeException(nameof(price), "Цена не может быть отрицательной."); + } + if (orderDates == null) + { + throw new ArgumentNullException(nameof(orderDates)); + } + + DateTime currentMonthStart = new DateTime(calculationDate.Year, calculationDate.Month, 1); + DateTime previousMonthStart = currentMonthStart.AddMonths(-1); + bool hasOrdersInPreviousMonth = orderDates.Any(date => date >= previousMonthStart && date < currentMonthStart); + + if (hasOrdersInPreviousMonth) + { + return price; + } + return Math.Round(price * (100m - DiscountPercent) / 100m, 2); + } + + /// + /// Возвращает признак количества: «много», если пар больше пяти, иначе «мало». + /// + /// Количество пар суммарно по всем размерам. + public static string GetQuantityLabel(int totalQuantity) + { + if (totalQuantity < 0) + { + throw new ArgumentOutOfRangeException(nameof(totalQuantity), "Количество не может быть отрицательным."); + } + return totalQuantity > ManyQuantityThreshold ? "много" : "мало"; + } + } +} diff --git a/ShoeStore.Logic/ShoeStore.Logic.csproj b/ShoeStore.Logic/ShoeStore.Logic.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/ShoeStore.Logic/ShoeStore.Logic.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/ShoeStore.Tests/MSTestSettings.cs b/ShoeStore.Tests/MSTestSettings.cs new file mode 100644 index 0000000..aaf278c --- /dev/null +++ b/ShoeStore.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/ShoeStore.Tests/ProductCalculatorTests.cs b/ShoeStore.Tests/ProductCalculatorTests.cs new file mode 100644 index 0000000..9a890a6 --- /dev/null +++ b/ShoeStore.Tests/ProductCalculatorTests.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ShoeStore.Logic; + +namespace ShoeStore.Tests +{ + [TestClass] + public class ProductCalculatorTests + { + // Случай 1: заказов в предыдущем месяце нет - цена со скидкой + [TestMethod] + public void CalculateDiscountedPrice_NoOrdersInPreviousMonth_ReturnsPriceWithDiscount() + { + decimal price = 2000m; + List orderDates = new List(); + DateTime calculationDate = new DateTime(2027, 6, 15); + + decimal result = ProductCalculator.CalculateDiscountedPrice(price, orderDates, calculationDate); + + Assert.AreEqual(1500m, result); + } + + // Случай 2: есть заказ в предыдущем месяце - цена без скидки + [TestMethod] + public void CalculateDiscountedPrice_OrderInPreviousMonth_ReturnsPriceWithoutDiscount() + { + decimal price = 2000m; + List orderDates = new List { new DateTime(2027, 5, 10) }; + DateTime calculationDate = new DateTime(2027, 6, 15); + + decimal result = ProductCalculator.CalculateDiscountedPrice(price, orderDates, calculationDate); + + Assert.AreEqual(2000m, result); + } + + // Случай 3: граничное значение - «мало» + [TestMethod] + public void GetQuantityLabel_FivePairs_ReturnsFew() + { + string result = ProductCalculator.GetQuantityLabel(5); + + Assert.AreEqual("мало", result); + } + + // Случай 4: больше порогового - «много» + [TestMethod] + public void GetQuantityLabel_SixPairs_ReturnsMany() + { + string result = ProductCalculator.GetQuantityLabel(6); + + Assert.AreEqual("много", result); + } + } +} diff --git a/ShoeStore.Tests/ShoeStore.Tests.csproj b/ShoeStore.Tests/ShoeStore.Tests.csproj new file mode 100644 index 0000000..9c96869 --- /dev/null +++ b/ShoeStore.Tests/ShoeStore.Tests.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + latest + enable + enable + + + + + + + + + + + + + + + + diff --git a/result.png b/result.png new file mode 100644 index 0000000..e28098a Binary files /dev/null and b/result.png differ