From e28db12d7e493042fe55eb45dd654a20bd89cd29 Mon Sep 17 00:00:00 2001 From: Azkraft Date: Mon, 27 Oct 2025 19:00:14 +0500 Subject: [PATCH 1/6] fix(ObjectComparison): migrate to FluentAssertions --- .../1. ObjectComparison/ObjectComparison.cs | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs index d544c47..85cb21d 100644 --- a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs +++ b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs @@ -1,9 +1,12 @@ -using NUnit.Framework; +using FluentAssertions; +using NUnit.Framework; using NUnit.Framework.Legacy; namespace HomeExercise.Tasks.ObjectComparison; public class ObjectComparison { + private const int MaxGenDepth = 1000; + [Test] [Description("Проверка текущего царя")] [Category("ToRefactor")] @@ -12,19 +15,23 @@ 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)); - - // Перепишите код на использование 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); - - 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); - } + new Person("Vasili III of Russia", 28, 170, 60, null!)); + + var currentActual = actualTsar; + var currentExpected = expectedTsar; + for (var i = 0; i > -MaxGenDepth; i--) + { + if (currentExpected is null && currentActual is null) + return; + + CheckTsarFields(currentActual, currentExpected, i); + + currentActual = currentActual?.Parent; + currentExpected = currentExpected?.Parent; + } + + Assert.Fail("The verification depth has reached its maximum value."); + } [Test] [Description("Альтернативное решение. Какие у него недостатки?")] @@ -32,13 +39,23 @@ 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)); + new Person("Vasili III of Russia", 28, 170, 60, null!)); // Какие недостатки у такого подхода? + + /* + * Мы не получаем полезной информации при падении теста. + * Было бы полезно знать в каком поле наблюдается различие. + * Также мы не знаем в каком поколении находится это различие. + * Кроме того, реализация AreEqual рекурсивная + * и при этом не защищена от замыкания (зацикливания) цепочки родословной. + * Несколько лучшим решением было бы реализовать класс с интерфейсом IEqualityComparer. + */ + ClassicAssert.True(AreEqual(actualTsar, expectedTsar)); } - private bool AreEqual(Person? actual, Person? expected) + private bool AreEqual(Person? actual, Person? expected) { if (actual == expected) return true; if (actual == null || expected == null) return false; @@ -49,4 +66,22 @@ private bool AreEqual(Person? actual, Person? expected) && actual.Weight == expected.Weight && AreEqual(actual.Parent, expected.Parent); } + + private void CheckTsarFields(Person? actual, Person? expected, int genNumber) + { + var message = $"the generation {genNumber}"; + + if (expected is null) + { + actual.Should().BeNull(message); + return; + } + + actual.Should().NotBeNull(message); + expected.Should().NotBeNull(message); + actual!.Name.Should().Be(expected!.Name, message); + actual!.Age.Should().Be(expected!.Age, message); + actual!.Height.Should().Be(expected!.Height, message); + actual!.Weight.Should().Be(expected!.Weight, message); + } } From bd269a2890b597a81126dc425516af1dacb2ebec Mon Sep 17 00:00:00 2001 From: Azkraft Date: Mon, 27 Oct 2025 21:12:28 +0500 Subject: [PATCH 2/6] fix(NumberValidatorTests): migrate to FluentAssertions and add extra tests --- .../NumberValidatorTests.cs | 84 ++++++++++++++----- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 950c9bc..037c7bc 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -1,31 +1,75 @@ - +using FluentAssertions; using NUnit.Framework; -using NUnit.Framework.Legacy; namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { - [Test] - public void Test() + [TestCase(-1)] + [TestCase(1, -1)] + [TestCase(1, 2)] + [TestCase(-1, 2, true)] + [TestCase(-1, 2, false)] + [TestCase(1, 0, false, false)] + public void CheckParametersValidation( + int precision, + int scale = 0, + bool onlyPositive = false, + bool shouldThrowException = true) { - 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)); + var func = () => new NumberValidator(precision, scale, onlyPositive); + var message = $""" + parameters are + precision: {precision}, + scale: {scale}, + onlyPositive: {onlyPositive} - 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")); + """; + + + if (shouldThrowException) + func.Should().Throw(message); + else + func.Should().NotThrow(message); + } + + [TestCase(null, false, 1)] + [TestCase("", false, 1)] + [TestCase(" \n\t ", false, 1)] + [TestCase("a.sd", false, 3, 2)] + [TestCase("0", true, 17, 2)] + [TestCase(" 0", false, 17, 2)] + [TestCase("0 ", false, 17, 2)] + [TestCase(".0", false, 17, 2)] + [TestCase("0.", false, 17, 2)] + [TestCase("0.0", true, 17, 2)] + [TestCase("0.00", true, 17, 2)] + [TestCase("0.000", false, 17, 2)] + [TestCase("00.00", false, 3, 2)] + [TestCase("-0.00", false, 3, 2)] + [TestCase("-0.00", false, 4, 2)] + [TestCase("-0.00", true, 4, 2, false)] + [TestCase("+0.00", false, 3, 2)] + [TestCase("+1.23", true, 4, 2)] + [TestCase("+1.23", false, 3, 2)] + [TestCase("-1.23", false, 3, 2)] + [TestCase("+123", true, 4)] + [TestCase("+123", false, 3)] + [TestCase("-123", false, 3)] + [TestCase("-123", false, 4)] + [TestCase("-123", true, 4, 0, false)] + [TestCase("123", true, 3)] + public void CheckNumberValidation( + string number, + bool isValid, + int precision, + int scale = 0, + bool onlyPositive = true) + { + new NumberValidator(precision, scale, onlyPositive) + .IsValidNumber(number) + .Should() + .Be(isValid); } } \ No newline at end of file From cab3453d707e94543eb7839b04f5d212a4851a7d Mon Sep 17 00:00:00 2001 From: Azkraft Date: Wed, 29 Oct 2025 06:38:42 +0500 Subject: [PATCH 3/6] fix(ObjectComparison): replaced by BeEquivalentTo --- .../1. ObjectComparison/ObjectComparison.cs | 38 +++---------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs index 85cb21d..e1ce895 100644 --- a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs +++ b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs @@ -17,21 +17,9 @@ public void CheckCurrentTsar() var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, new Person("Vasili III of Russia", 28, 170, 60, null!)); - var currentActual = actualTsar; - var currentExpected = expectedTsar; - for (var i = 0; i > -MaxGenDepth; i--) - { - if (currentExpected is null && currentActual is null) - return; - - CheckTsarFields(currentActual, currentExpected, i); - - currentActual = currentActual?.Parent; - currentExpected = currentExpected?.Parent; - } - - Assert.Fail("The verification depth has reached its maximum value."); - } + actualTsar.Should().BeEquivalentTo(expectedTsar, options => options + .Excluding(info => info.Path.EndsWith(nameof(Person.Id)))); + } [Test] [Description("Альтернативное решение. Какие у него недостатки?")] @@ -50,6 +38,8 @@ public void CheckCurrentTsar_WithCustomEquality() * Кроме того, реализация AreEqual рекурсивная * и при этом не защищена от замыкания (зацикливания) цепочки родословной. * Несколько лучшим решением было бы реализовать класс с интерфейсом IEqualityComparer. + * Реализация равенства не связана с классом Person, + * поэтому при изменении класса нужно не забывать о необходимости внесения правок в эту реализацию. */ ClassicAssert.True(AreEqual(actualTsar, expectedTsar)); @@ -66,22 +56,4 @@ private bool AreEqual(Person? actual, Person? expected) && actual.Weight == expected.Weight && AreEqual(actual.Parent, expected.Parent); } - - private void CheckTsarFields(Person? actual, Person? expected, int genNumber) - { - var message = $"the generation {genNumber}"; - - if (expected is null) - { - actual.Should().BeNull(message); - return; - } - - actual.Should().NotBeNull(message); - expected.Should().NotBeNull(message); - actual!.Name.Should().Be(expected!.Name, message); - actual!.Age.Should().Be(expected!.Age, message); - actual!.Height.Should().Be(expected!.Height, message); - actual!.Weight.Should().Be(expected!.Weight, message); - } } From 541000a79037f0fd72f920e38b09cc74e28f01c8 Mon Sep 17 00:00:00 2001 From: Azkraft Date: Wed, 29 Oct 2025 08:52:22 +0500 Subject: [PATCH 4/6] fix(NumberValidatorTests): rewrite all tests --- .../NumberValidatorTests.cs | 152 ++++++++++++------ 1 file changed, 100 insertions(+), 52 deletions(-) diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 037c7bc..9f6cc8f 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -6,70 +6,118 @@ namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { - [TestCase(-1)] - [TestCase(1, -1)] - [TestCase(1, 2)] - [TestCase(-1, 2, true)] - [TestCase(-1, 2, false)] - [TestCase(1, 0, false, false)] - public void CheckParametersValidation( + [TestCase(-1, 0, false, "Non-positive total number of digits")] + [TestCase(1, -1, false, "Negative number of digits in fractional part")] + [TestCase(1, 2, false, + "Number of digits in fractional part greater or equal to total number of digits")] + public void NumberValidatorConstructor_ShouldThrow_ArgumentException( int precision, - int scale = 0, - bool onlyPositive = false, - bool shouldThrowException = true) + int scale, + bool onlyPositive, + string message) { var func = () => new NumberValidator(precision, scale, onlyPositive); - var message = $""" - parameters are - precision: {precision}, - scale: {scale}, - onlyPositive: {onlyPositive} - """; + func.Should().Throw(message); + } + [TestCase(1, 0, false, + "Positive precision, non-negative scale and scale less than precision")] + public void NumberValidatorConstructor_ShouldNotThrow_Exception( + int precision, + int scale, + bool onlyPositive, + string message) + { + var func = () => new NumberValidator(precision, scale, onlyPositive); + + func.Should().NotThrow(message); + } - if (shouldThrowException) - func.Should().Throw(message); - else - func.Should().NotThrow(message); - } + [TestCase(null, 17, 2, true)] + [TestCase("", 17, 2, true)] + [TestCase(" \n\t ", 17, 2, true)] + public void IsValidNumber_ShouldBe_False_When_NullOrEmpty( + string number, + int precision, + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, false); - [TestCase(null, false, 1)] - [TestCase("", false, 1)] - [TestCase(" \n\t ", false, 1)] - [TestCase("a.sd", false, 3, 2)] - [TestCase("0", true, 17, 2)] - [TestCase(" 0", false, 17, 2)] - [TestCase("0 ", false, 17, 2)] - [TestCase(".0", false, 17, 2)] - [TestCase("0.", false, 17, 2)] - [TestCase("0.0", true, 17, 2)] - [TestCase("0.00", true, 17, 2)] - [TestCase("0.000", false, 17, 2)] - [TestCase("00.00", false, 3, 2)] - [TestCase("-0.00", false, 3, 2)] - [TestCase("-0.00", false, 4, 2)] - [TestCase("-0.00", true, 4, 2, false)] - [TestCase("+0.00", false, 3, 2)] - [TestCase("+1.23", true, 4, 2)] - [TestCase("+1.23", false, 3, 2)] - [TestCase("-1.23", false, 3, 2)] - [TestCase("+123", true, 4)] - [TestCase("+123", false, 3)] - [TestCase("-123", false, 3)] - [TestCase("-123", false, 4)] - [TestCase("-123", true, 4, 0, false)] - [TestCase("123", true, 3)] - public void CheckNumberValidation( + [TestCase("asd", 17, 2, true)] + [TestCase(" 0", 17, 2, true)] + [TestCase("0 ", 17, 2, true)] + [TestCase(".0", 17, 2, true)] + [TestCase("0.", 17, 2, true)] + [TestCase("a23", 17, 2, true)] + [TestCase("1e3", 17, 2, true)] + [TestCase("1.a23", 17, 2, true)] + public void IsValidNumber_ShouldBe_False_When_DoesNotMatchFormat( string number, - bool isValid, int precision, - int scale = 0, - bool onlyPositive = true) + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, false); + + [TestCase("00.00", 3, 2, true)] + [TestCase("-0.00", 3, 2, false)] + [TestCase("+123", 3, 2, true)] + [TestCase("1234", 3, 2, true)] + public void IsValidNumber_ShouldBe_False_When_DigitsPlusSignGreaterPrecision( + string number, + int precision, + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, false); + + [TestCase("00.00", 4, 2, true)] + [TestCase("-0.00", 4, 2, false)] + [TestCase("+123", 4, 2, true)] + [TestCase("1234", 4, 2, true)] + public void IsValidNumber_ShouldBe_True_When_DigitsPlusSignLessOrEqualPrecision( + string number, + int precision, + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, true); + + [TestCase("0.000", 17, 2, true)] + public void IsValidNumber_ShouldBe_False_When_FractionGreaterScale( + string number, + int precision, + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, false); + + [TestCase("0", 17, 2, true)] + [TestCase("0.0", 17, 2, true)] + [TestCase("0.00", 17, 2, true)] + public void IsValidNumber_ShouldBe_True_When_FractionLessOrEqualScale( + string number, + int precision, + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, true); + + [TestCase("-0.00", 4, 2, true)] + [TestCase("-123", 4, 2, true)] + public void IsValidNumber_ShouldBe_False_When_MinusAndOnlyPositive( + string number, + int precision, + int scale, + bool onlyPositive) + => CheckNumberValidation(number, precision, scale, onlyPositive, false); + + private void CheckNumberValidation( + string number, + int precision, + int scale, + bool onlyPositive, + bool isValid) { new NumberValidator(precision, scale, onlyPositive) .IsValidNumber(number) .Should() .Be(isValid); - } + } } \ No newline at end of file From a3c24259cfd4ed3fe68e8ec58e55c31270299f91 Mon Sep 17 00:00:00 2001 From: Azkraft Date: Wed, 29 Oct 2025 19:31:43 +0500 Subject: [PATCH 5/6] fix(ObjectComparison): bug with members excluding --- .../Homework/1. ObjectComparison/ObjectComparison.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs index e1ce895..1f97bf7 100644 --- a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs +++ b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs @@ -5,8 +5,6 @@ namespace HomeExercise.Tasks.ObjectComparison; public class ObjectComparison { - private const int MaxGenDepth = 1000; - [Test] [Description("Проверка текущего царя")] [Category("ToRefactor")] @@ -16,9 +14,11 @@ public void CheckCurrentTsar() var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, new Person("Vasili III of Russia", 28, 170, 60, null!)); - + actualTsar.Should().BeEquivalentTo(expectedTsar, options => options - .Excluding(info => info.Path.EndsWith(nameof(Person.Id)))); + .Excluding(info => + info.Path == nameof(Person.Id) + || info.Path.EndsWith($".{nameof(Person.Id)}"))); } [Test] From dd6df30ea2258b2aaf11a4e83ece73df68940657 Mon Sep 17 00:00:00 2001 From: Azkraft Date: Wed, 29 Oct 2025 19:34:29 +0500 Subject: [PATCH 6/6] fix(NumberValidator): edit tests' names --- .../NumberValidatorTests.cs | 78 +++++++++++++------ 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 9f6cc8f..7c92b9d 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -6,35 +6,49 @@ namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { - [TestCase(-1, 0, false, "Non-positive total number of digits")] - [TestCase(1, -1, false, "Negative number of digits in fractional part")] - [TestCase(1, 2, false, - "Number of digits in fractional part greater or equal to total number of digits")] - public void NumberValidatorConstructor_ShouldThrow_ArgumentException( - int precision, - int scale, - bool onlyPositive, - string message) - { - var func = () => new NumberValidator(precision, scale, onlyPositive); + [TestCase(-1, 0, false)] + public void Constructor_ShouldThrow_ArgumentException_When_NegativeTotalNumberOfDigits( + int precision, + int scale, + bool onlyPositive) + => CheckConstructorThrowArgumentException(precision, scale, onlyPositive, true); - func.Should().Throw(message); - } + [TestCase(0, 0, false)] + public void Constructor_ShouldThrow_ArgumentException_When_ZeroTotalNumberOfDigits( + int precision, + int scale, + bool onlyPositive) + => CheckConstructorThrowArgumentException(precision, scale, onlyPositive, true); + + [TestCase(1, -1, false)] + public void Constructor_ShouldThrow_ArgumentException_When_NegativeNumberOfDigitsInFractionalPart( + int precision, + int scale, + bool onlyPositive) + => CheckConstructorThrowArgumentException(precision, scale, onlyPositive, true); + + [TestCase(1, 1, false)] + public void Constructor_ShouldThrow_ArgumentException_When_NumberOfDigitsInFractionalPartEqualTotalNumberOfDigits( + int precision, + int scale, + bool onlyPositive) + => CheckConstructorThrowArgumentException(precision, scale, onlyPositive, true); + + [TestCase(1, 2, false)] + public void Constructor_ShouldThrow_ArgumentException_When_NumberOfDigitsInFractionalPartGreaterTotalNumberOfDigits( + int precision, + int scale, + bool onlyPositive) + => CheckConstructorThrowArgumentException(precision, scale, onlyPositive, true); - [TestCase(1, 0, false, - "Positive precision, non-negative scale and scale less than precision")] - public void NumberValidatorConstructor_ShouldNotThrow_Exception( + [TestCase(1, 0, false)] + public void Constructor_ShouldNotThrow_Exception_When_PositivePrecisionNonNegativeScaleAndScaleLessPrecision( int precision, int scale, - bool onlyPositive, - string message) - { - var func = () => new NumberValidator(precision, scale, onlyPositive); - - func.Should().NotThrow(message); - } + bool onlyPositive) + => CheckConstructorThrowArgumentException(precision, scale, onlyPositive, false); - [TestCase(null, 17, 2, true)] + [TestCase(null, 17, 2, true)] [TestCase("", 17, 2, true)] [TestCase(" \n\t ", 17, 2, true)] public void IsValidNumber_ShouldBe_False_When_NullOrEmpty( @@ -51,7 +65,7 @@ public void IsValidNumber_ShouldBe_False_When_NullOrEmpty( [TestCase("0.", 17, 2, true)] [TestCase("a23", 17, 2, true)] [TestCase("1e3", 17, 2, true)] - [TestCase("1.a23", 17, 2, true)] + [TestCase("1.a23", 17, 5, true)] public void IsValidNumber_ShouldBe_False_When_DoesNotMatchFormat( string number, int precision, @@ -120,4 +134,18 @@ private void CheckNumberValidation( .Should() .Be(isValid); } + + private void CheckConstructorThrowArgumentException( + int precision, + int scale, + bool onlyPositive, + bool shouldThrow) + { + var func = () => new NumberValidator(precision, scale, onlyPositive); + + if (shouldThrow) + func.Should().Throw(); + else + func.Should().NotThrow(); + } } \ No newline at end of file