diff --git a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs index d544c47..0ac7bdd 100644 --- a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs +++ b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs @@ -1,8 +1,10 @@ -using NUnit.Framework; +using FluentAssertions; +using NUnit.Framework; using NUnit.Framework.Legacy; namespace HomeExercise.Tasks.ObjectComparison; -public class ObjectComparison + +public class TsarComparison { [Test] [Description("Проверка текущего царя")] @@ -11,19 +13,27 @@ public void CheckCurrentTsar() { var actualTsar = TsarRegistry.GetCurrentTsar(); - var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, - new Person("Vasili III of Russia", 28, 170, 60, null)); + var expectedTsar = new Person( + name: "Ivan IV The Terrible", + age: 54, + height: 170, + weight: 70, + parent: new Person( + name: "Vasili III of Russia", + age: 28, + height: 170, + weight: 60, + parent: null! + ) + ); - // Перепишите код на использование Fluent Assertions. - ClassicAssert.AreEqual(actualTsar.Name, expectedTsar.Name); - ClassicAssert.AreEqual(actualTsar.Age, expectedTsar.Age); - ClassicAssert.AreEqual(actualTsar.Height, expectedTsar.Height); - ClassicAssert.AreEqual(actualTsar.Weight, expectedTsar.Weight); + /// + /// Такой подход автоматически проверяет все свойства объекта, включая вложенные + /// Тест не будет требовать изменений при добавлении новых свойств в класс Person + /// При падении теста, FluentAssertions предоставляет подробную информацию о том, какие именно свойства не совпали + /// - ClassicAssert.AreEqual(expectedTsar.Parent!.Name, actualTsar.Parent!.Name); - ClassicAssert.AreEqual(expectedTsar.Parent.Age, actualTsar.Parent.Age); - ClassicAssert.AreEqual(expectedTsar.Parent.Height, actualTsar.Parent.Height); - ClassicAssert.AreEqual(expectedTsar.Parent.Parent, actualTsar.Parent.Parent); + actualTsar.Should().BeEquivalentTo(expectedTsar, options => options.Excluding(t => t.Id).Excluding(t => t.Parent.Id)); } [Test] @@ -31,11 +41,35 @@ public void CheckCurrentTsar() public void CheckCurrentTsar_WithCustomEquality() { var actualTsar = TsarRegistry.GetCurrentTsar(); - var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, - new Person("Vasili III of Russia", 28, 170, 60, null)); - - // Какие недостатки у такого подхода? + + var expectedTsar = new Person( + name: "Ivan IV The Terrible", + age: 54, + height: 170, + weight: 70, + new Person( + name: "Vasili III of Russia", + age: 28, + height: 170, + weight: 60, + parent: null! + ) + ); + + // Какие недостатки у такого подхода? + // Недостатки подхода: + // 1) Требуется ручное обновление метода сравнения при добавлении новых свойств в класс Person, + // 2) Тест менее информативен при падении. Он просто укажет, что объекты не равны, не показывая какие именно свойства не совпали. ClassicAssert.True(AreEqual(actualTsar, expectedTsar)); + + // Вызываем Stack Overflow exception + // var p1 = new Person("A", 1, 1, 1, null!); + // p1.Parent = p1; + // + // var p2 = new Person("A", 1, 1, 1, null!); + // p2.Parent = p2; + // + // ClassicAssert.True(AreEqual(p1, p2)); } private bool AreEqual(Person? actual, Person? expected) @@ -49,4 +83,4 @@ private bool AreEqual(Person? actual, Person? expected) && actual.Weight == expected.Weight && AreEqual(actual.Parent, expected.Parent); } -} +} \ No newline at end of file diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 950c9bc..60e4827 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -1,31 +1,209 @@ - +using FluentAssertions; using NUnit.Framework; -using NUnit.Framework.Legacy; namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { + #region Допустимая разрядность + + [TestCase(-1, 2, true)] + [TestCase(0, 2, true)] + public void Ctor_InvalidPrecision_ThrowsArgumentException(int precision, int scale, bool onlyPositive) + { + var act = () => new NumberValidator(precision, scale, onlyPositive); + act.Should() + .Throw() + .WithMessage("precision must be a positive number"); + } + + #endregion + + #region Некорректная дробность + + [TestCase(5, -1, true)] + public void Ctor_InvalidScale_Negative_ThrowsArgumentException(int precision, int scale, bool onlyPositive) + { + var act = () => new NumberValidator(precision, scale, onlyPositive); + act.Should() + .Throw() + .WithMessage("*non-negative*"); // узнал, что можно передавать часть строки + } + + [TestCase(1, 2, true)] + [TestCase(1, 1, true)] + public void Ctor_WithScaleGreaterOrEqualToPrecision_ThrowsArgumentException(int precision, int scale, bool onlyPositive) + { + var act = () => new NumberValidator(precision, scale, onlyPositive); + act.Should() + .Throw() + .WithMessage("*less or equal*"); // узнал, что можно передавать часть строки + } + + #endregion + + #region Корректные аргументы для конструктора + + [Test] + public void Ctor_ValidArguments_DoesNotThrow() + { + var act = () => new NumberValidator(1, 0, true); + act.Should().NotThrow(); + } + + #endregion + + #region Передаваемое число в формате пустой строки или null + + [TestCase("", 17, 2, true)] + [TestCase(null, 17, 2, true)] + public void IsValidNumber_NullOrEmpty_ReturnsFalse(string value, int precision, int scale, bool onlyPositive) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + var result = validator.IsValidNumber(value); + result.Should().BeFalse(); + } + + #endregion + + #region Некорректный формат передаваемого числа + + [Test] + public void IsValidNumber_MultipleFractionSeparators_ReturnsFalse() + { + var validator = new NumberValidator(10, 4, true); + var result = validator.IsValidNumber("1..2"); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_OnlySigns_ReturnsFalse() + { + var validator = new NumberValidator(15, 1, true); + var result = validator.IsValidNumber("+-."); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_OnlyDot_ReturnsFalse() + { + var validator = new NumberValidator(22, 8, true); + var result = validator.IsValidNumber("."); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_DotLastSign_ReturnsFalse() + { + var validator = new NumberValidator(9, 4, true); + var result = validator.IsValidNumber("1."); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_DotFirstSign_ReturnsFalse() + { + var validator = new NumberValidator(7, 3, true); + var result = validator.IsValidNumber(".1"); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_ContainsSpace_ReturnsFalse() + { + var validator = new NumberValidator(17, 6, true); + var result = validator.IsValidNumber("5 2"); + result.Should().BeFalse(); + } + [Test] - public void Test() - { - Assert.Throws(() => new NumberValidator(-1, 2, true)); - Assert.DoesNotThrow(() => new NumberValidator(1, 0, true)); - Assert.Throws(() => new NumberValidator(-1, 2, false)); - Assert.DoesNotThrow(() => new NumberValidator(1, 0, true)); - - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0")); - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("00.00")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-0.00")); - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+0.00")); - ClassicAssert.IsTrue(new NumberValidator(4, 2, true).IsValidNumber("+1.23")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+1.23")); - ClassicAssert.IsFalse(new NumberValidator(17, 2, true).IsValidNumber("0.000")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-1.23")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("a.sd")); + public void IsValidNumber_ContainsUnderscore_ReturnsFalse() + { + var validator = new NumberValidator(11, 3, true); + var result = validator.IsValidNumber("4_4"); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_ContainsLettersAndUnderscore_ReturnsFalse() + { + var validator = new NumberValidator(10, 5, true); + var result = validator.IsValidNumber("abcd_4"); + result.Should().BeFalse(); + } + + [Test] + public void IsValidNumber_DoubleMinus_ReturnsFalse() + { + var validator = new NumberValidator(12, 2, true); + var result = validator.IsValidNumber("--1"); + result.Should().BeFalse(); + } + + #endregion + + #region Корректное передаваемое число + + [TestCase("+1", 4, 2, true)] + [TestCase("+0.1", 9, 1, true)] + [TestCase("000.10", 5, 2, true)] + [TestCase("000,10", 8, 4, true)] + [TestCase("10", 2, 0, true)] + public void IsValidNumber_ValidFormat_ReturnsTrue(string value, int precision, int scale, bool onlyPositive) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + var result = validator.IsValidNumber(value); + result.Should().BeTrue(); + } + + #endregion + + #region Количество допустимых цифр в числе, включая знак, целую и дробную часть, без точки + + [TestCase("17.9", 3, 1, true, true)] + [TestCase("171.9", 3, 1, true, false)] + [TestCase("+17", 3, 2, true, true)] + [TestCase("+17", 2, 0, true, false)] + public void IsValidNumber_RespectsPrecisionLimit_ReturnsExpected(string value, int precision, int scale, + bool onlyPositive, bool expected) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + var result = validator.IsValidNumber(value); + result.Should().Be(expected); + } + + #endregion + + #region Количество знаков после запятой + + [TestCase("1.0", 10, 0, true, false)] + [TestCase("1.44", 10, 2, true, true)] + [TestCase("1.4", 10, 2, true, true)] + [TestCase("1,040", 10, 3, true, true)] + [TestCase("1.41414141", 10, 2, true, false)] + public void IsValidNumber_RespectsScale_ReturnsExpected(string value, int precision, int scale, bool onlyPositive, + bool expected) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + var result = validator.IsValidNumber(value); + result.Should().Be(expected); + } + + #endregion + + #region Проверка параметра onlyPositive (только положительные) + + [TestCase("-4.59", 4, 2, false, true)] + [TestCase("-6", 2, 0, true, false)] + [TestCase("+5", 2, 0, false, true)] + public void IsValidNumber_RespectsOnlyPositive_ReturnsExpected(string value, int precision, int scale, bool onlyPositive, + bool expected) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + var result = validator.IsValidNumber(value); + result.Should().Be(expected); } + + #endregion } \ No newline at end of file