From da2fc5c45394cc582ea12ae4f4b3dc14bbcf1cd6 Mon Sep 17 00:00:00 2001 From: daHil Date: Sun, 26 Nov 2023 17:15:21 +0500 Subject: [PATCH 1/6] refactored tests --- cs/HomeExercises/HomeExercises.csproj | 2 +- cs/HomeExercises/NumberValidatorTests.cs | 186 +++++++++++++++-------- cs/HomeExercises/ObjectComparison.cs | 154 ++++++++++--------- 3 files changed, 210 insertions(+), 132 deletions(-) diff --git a/cs/HomeExercises/HomeExercises.csproj b/cs/HomeExercises/HomeExercises.csproj index ede81aec..3d6fba00 100644 --- a/cs/HomeExercises/HomeExercises.csproj +++ b/cs/HomeExercises/HomeExercises.csproj @@ -14,7 +14,7 @@ - + \ No newline at end of file diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs index a2878113..76555a66 100644 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ b/cs/HomeExercises/NumberValidatorTests.cs @@ -1,80 +1,140 @@ using System; using System.Text.RegularExpressions; using FluentAssertions; +using FluentAssertions.Execution; +using static FluentAssertions.FluentActions; using NUnit.Framework; +using System.Collections; namespace HomeExercises { - public class NumberValidatorTests - { - [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)); + [TestFixture] + public class NumberValidatorTests + { + public static IEnumerable IsValidNumberPrecisionTests + { + get + { + yield return new TestCaseData(3, 2, true, "+0.00").Returns(false) + .SetName("IsValidNumber_ReturnsFalse_WhenSymbolWithNumberLengthGreaterThanPrecision"); + yield return new TestCaseData(3, 2, true, "00.00").Returns(false) + .SetName("IsValidNumber_ReturnsFalse_WhenIntPartWithFracPartGreaterThanPrecision"); + yield return new TestCaseData(17, 2, true, "0").Returns(true) + .SetName("IsValidNumber_ReturnsTrue_WhenNumberLengthNotGreaterThanPrecision"); + yield return new TestCaseData(4, 2, true, "+1.23").Returns(true) + .SetName("IsValidNumber_ReturnsTrue_WhenPositiveSymbolWithNumberLengthNotGreaterThanPrecision"); + yield return new TestCaseData(4, 2, false, "-1.23").Returns(true) + .SetName("IsValidNumber_ReturnsTrue_WhenNegativeSymbolWithNumberLengthNotGreaterThanPrecision"); + } + } + public static IEnumerable IsValidNumberScaleTests + { + get + { + yield return new TestCaseData(17, 2, true, "0.000").Returns(false) + .SetName("IsValidNumber_ReturnsFalse_WhenFracPartGreaterThanScale"); + yield return new TestCaseData(17, 2, true, "0.0").Returns(true) + .SetName("IsValidNumber_ReturnsTrue_WhenFracPartNotGreaterThanScale"); + } + } + public static IEnumerable IsValidNumberPositivityTests + { + get + { + yield return new TestCaseData(3, 2, true, "-0.00").Returns(false) + .SetName("IsValidNumber_ReturnsFalse_WhenAcceptsOnlyPositiveButGivenNegativeNumber"); + yield return new TestCaseData(3, 2, false, "-0.0").Returns(true) + .SetName("IsValidNumber_ReturnsTrue_WhenAcceptsAnyAndGivenNegativeNumber"); + } + } + public static IEnumerable IsValidNumberSymbolsTests + { + get + { + yield return new TestCaseData(3, 2, true, "a.sd").Returns(false) + .SetName("IsValidNumber_ReturnsFalse_WhenGivenNotDigits"); + yield return new TestCaseData(17, 2, true, "").Returns(false) + .SetName("IsValidNumber_ReturnsFalse_WhenEmptyStringGiven"); + } + } - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0")); - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("00.00")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-0.00")); - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+0.00")); - Assert.IsTrue(new NumberValidator(4, 2, true).IsValidNumber("+1.23")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+1.23")); - Assert.IsFalse(new NumberValidator(17, 2, true).IsValidNumber("0.000")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-1.23")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("a.sd")); - } - } - public class NumberValidator - { - private readonly Regex numberRegex; - private readonly bool onlyPositive; - private readonly int precision; - private readonly int scale; + public static IEnumerable ConstructorArgumentExceptions + { + get + { + yield return new TestCaseData(-1,2,true) + .SetName("Constructor_ThrowsArgumentExceptionWhenPercisionNotPositive"); + yield return new TestCaseData(1,2,true) + .SetName("Constructor_ThrowsArgumentExceptionWhenScaleGreaterThanPercision"); + yield return new TestCaseData(1,-1,true) + .SetName("Constructor_ThrowsArgumentExceptionWhenScaleNotPositive"); + yield return new TestCaseData(1,1,true) + .SetName("Constructor_ThrowsArgumentExceptionWhenScaleEqualsPercision"); + } + } - public NumberValidator(int precision, int scale = 0, bool onlyPositive = false) - { - this.precision = precision; - this.scale = scale; - this.onlyPositive = onlyPositive; - if (precision <= 0) - throw new ArgumentException("precision must be a positive number"); - if (scale < 0 || scale >= precision) - throw new ArgumentException("precision must be a non-negative number less or equal than precision"); - numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase); - } + [Test, TestCaseSource(nameof(IsValidNumberPositivityTests)), + TestCaseSource(nameof(IsValidNumberPrecisionTests)), + TestCaseSource(nameof(IsValidNumberScaleTests)), + TestCaseSource(nameof(IsValidNumberSymbolsTests))] + public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, string number) + { + return new NumberValidator(precision, scale, onlyPositive).IsValidNumber(number); + } - public bool IsValidNumber(string value) - { - // Проверяем соответствие входного значения формату N(m,k), в соответствии с правилом, - // описанным в Формате описи документов, направляемых в налоговый орган в электронном виде по телекоммуникационным каналам связи: - // Формат числового значения указывается в виде N(m.к), где m – максимальное количество знаков в числе, включая знак (для отрицательного числа), - // целую и дробную часть числа без разделяющей десятичной точки, k – максимальное число знаков дробной части числа. - // Если число знаков дробной части числа равно 0 (т.е. число целое), то формат числового значения имеет вид N(m). + [Test, TestCaseSource(nameof(ConstructorArgumentExceptions))] + public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) + { + Invoking(() => new NumberValidator(precision, scale, onlyPositive)).Should().Throw(); + } + } - if (string.IsNullOrEmpty(value)) - return false; + public class NumberValidator + { + private readonly Regex numberRegex; + private readonly bool onlyPositive; + private readonly int precision; + private readonly int scale; - var match = numberRegex.Match(value); - if (!match.Success) - return false; + public NumberValidator(int precision, int scale = 0, bool onlyPositive = false) + { + this.precision = precision; + this.scale = scale; + this.onlyPositive = onlyPositive; + if (precision <= 0) + throw new ArgumentException("precision must be a positive number"); + if (scale < 0 || scale >= precision) + throw new ArgumentException("precision must be a non-negative number less or equal than precision"); + numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase); + } - // Знак и целая часть - var intPart = match.Groups[1].Value.Length + match.Groups[2].Value.Length; - // Дробная часть - var fracPart = match.Groups[4].Value.Length; + public bool IsValidNumber(string value) + { + // Проверяем соответствие входного значения формату N(m,k), в соответствии с правилом, + // описанным в Формате описи документов, направляемых в налоговый орган в электронном виде по телекоммуникационным каналам связи: + // Формат числового значения указывается в виде N(m.к), где m – максимальное количество знаков в числе, включая знак (для отрицательного числа), + // целую и дробную часть числа без разделяющей десятичной точки, k – максимальное число знаков дробной части числа. + // Если число знаков дробной части числа равно 0 (т.е. число целое), то формат числового значения имеет вид N(m). - if (intPart + fracPart > precision || fracPart > scale) - return false; + if (string.IsNullOrEmpty(value)) + return false; - if (onlyPositive && match.Groups[1].Value == "-") - return false; - return true; - } - } + var match = numberRegex.Match(value); + if (!match.Success) + return false; + + // Знак и целая часть + var intPart = match.Groups[1].Value.Length + match.Groups[2].Value.Length; + // Дробная часть + var fracPart = match.Groups[4].Value.Length; + + if (intPart + fracPart > precision || fracPart > scale) + return false; + + if (onlyPositive && match.Groups[1].Value == "-") + return false; + return true; + } + } } \ No newline at end of file diff --git a/cs/HomeExercises/ObjectComparison.cs b/cs/HomeExercises/ObjectComparison.cs index 44d9aed4..2d022193 100644 --- a/cs/HomeExercises/ObjectComparison.cs +++ b/cs/HomeExercises/ObjectComparison.cs @@ -1,83 +1,101 @@ using FluentAssertions; using NUnit.Framework; +using System.Net; namespace HomeExercises { - public class ObjectComparison - { - [Test] - [Description("Проверка текущего царя")] - [Category("ToRefactor")] - public void CheckCurrentTsar() - { - var actualTsar = TsarRegistry.GetCurrentTsar(); + public class ObjectComparison + { + [Test] + [Description("Проверка текущего царя")] + [Category("ToRefactor")] + 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("Ivan IV The Terrible", 54, 170, 70, + new Person("Vasili III of Russia", 28, 170, 60, null)); - // Перепишите код на использование Fluent Assertions. - Assert.AreEqual(actualTsar.Name, expectedTsar.Name); - Assert.AreEqual(actualTsar.Age, expectedTsar.Age); - Assert.AreEqual(actualTsar.Height, expectedTsar.Height); - Assert.AreEqual(actualTsar.Weight, expectedTsar.Weight); + // сравнение родителей такое же как и в коде, который нужно было отрефакторить - сравнивает по ссылке, + // а значит при создании экземпляра для сравнения, если родитель родителя будет не null, + // то будет ошибка, если это не ошибка в тесте, а так и должно быть, + // то реализация CheckCurrentTsar_WithCustomEquality работает неправильно, + // тк в таком случае она засчитает тест + // также данная реализация CheckCurrentTsar не сравнивает поле Weight для родителя, + // также как и оригинальный код, из-за чего данная реализация + // будет показывать результат отличный от CheckCurrentTsar_WithCustomEquality при + // небольших изменениях в TsarRegistry или в экземпляре expectedTsar - Assert.AreEqual(expectedTsar.Parent!.Name, actualTsar.Parent!.Name); - Assert.AreEqual(expectedTsar.Parent.Age, actualTsar.Parent.Age); - Assert.AreEqual(expectedTsar.Parent.Height, actualTsar.Parent.Height); - Assert.AreEqual(expectedTsar.Parent.Parent, actualTsar.Parent.Parent); - } + actualTsar.Should().BeEquivalentTo(expectedTsar, options => options + .Excluding(tsar => tsar.Id) + .Excluding(tsar => tsar.Parent)); + expectedTsar.Parent.Should().BeEquivalentTo(actualTsar.Parent!, options => options + .Excluding(parent => parent.Id) + .Excluding(parent => parent.Weight)); - [Test] - [Description("Альтернативное решение. Какие у него недостатки?")] - 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)); + // данная реализация лучше CheckCurrentTsar_WithCustomEquality тем, что: + // 1) при ошибке в тесте, выводится объяснение того, что пошло не так + // 2) код теста легко читается - методы записаны последовательно, и что они делают понятно из названия + // 3) название теста на прямую отражает происходящее в коде и соответствует выводимому результату + // 4) более удобная в плане расширяемости - // Какие недостатки у такого подхода? - Assert.True(AreEqual(actualTsar, expectedTsar)); - } + } - private bool AreEqual(Person? actual, Person? expected) - { - if (actual == expected) return true; - if (actual == null || expected == null) return false; - return - actual.Name == expected.Name - && actual.Age == expected.Age - && actual.Height == expected.Height - && actual.Weight == expected.Weight - && AreEqual(actual.Parent, expected.Parent); - } - } + [Test] + [Description("Альтернативное решение. Какие у него недостатки?")] + 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)); - public class TsarRegistry - { - public static Person GetCurrentTsar() - { - return new Person( - "Ivan IV The Terrible", 54, 170, 70, - new Person("Vasili III of Russia", 28, 170, 60, null)); - } - } + // Какие недостатки у такого подхода? + // 1) функциональность теста разбита на 2 метода, усложняя его читаемость + // 2) тест уже посути не сравнивает царей, а проверяет работу метода AreEqual + // 3) отсутствие пояснения - только выкинет "ожидается true, а было false" при ошибке + // 4) такая реализация AreEqual может вызвать переполнение стэка, тк сравнение родителей рекурсивно + Assert.True(AreEqual(actualTsar, expectedTsar)); + } - public class Person - { - public static int IdCounter = 0; - public int Age, Height, Weight; - public string Name; - public Person? Parent; - public int Id; + private bool AreEqual(Person? actual, Person? expected) + { + if (actual == expected) return true; + if (actual == null || expected == null) return false; + return + actual.Name == expected.Name + && actual.Age == expected.Age + && actual.Height == expected.Height + && actual.Weight == expected.Weight + && AreEqual(actual.Parent, expected.Parent); + } + } - public Person(string name, int age, int height, int weight, Person? parent) - { - Id = IdCounter++; - Name = name; - Age = age; - Height = height; - Weight = weight; - Parent = parent; - } - } + public class TsarRegistry + { + public static Person GetCurrentTsar() + { + return new Person( + "Ivan IV The Terrible", 54, 170, 70, + new Person("Vasili III of Russia", 28, 170, 60, null)); + } + } + + public class Person + { + public static int IdCounter = 0; + public int Age, Height, Weight; + public string Name; + public Person? Parent; + public int Id; + + public Person(string name, int age, int height, int weight, Person? parent) + { + Id = IdCounter++; + Name = name; + Age = age; + Height = height; + Weight = weight; + Parent = parent; + } + } } \ No newline at end of file From a703de1e8a29042485d2938a00a3c8a5d3e595b2 Mon Sep 17 00:00:00 2001 From: daHil Date: Tue, 28 Nov 2023 18:42:34 +0500 Subject: [PATCH 2/6] refactored after reseting branch --- cs/HomeExercises/NumberValidatorTests.cs | 118 +++++++++++++---------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs index 76555a66..0eaae55a 100644 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ b/cs/HomeExercises/NumberValidatorTests.cs @@ -2,92 +2,108 @@ using System.Text.RegularExpressions; using FluentAssertions; using FluentAssertions.Execution; -using static FluentAssertions.FluentActions; using NUnit.Framework; using System.Collections; +using System.Collections.Generic; namespace HomeExercises { [TestFixture] public class NumberValidatorTests { - public static IEnumerable IsValidNumberPrecisionTests + private static IEnumerable IsValidNumberPrecisionTests { get { - yield return new TestCaseData(3, 2, true, "+0.00").Returns(false) - .SetName("IsValidNumber_ReturnsFalse_WhenSymbolWithNumberLengthGreaterThanPrecision"); - yield return new TestCaseData(3, 2, true, "00.00").Returns(false) - .SetName("IsValidNumber_ReturnsFalse_WhenIntPartWithFracPartGreaterThanPrecision"); - yield return new TestCaseData(17, 2, true, "0").Returns(true) - .SetName("IsValidNumber_ReturnsTrue_WhenNumberLengthNotGreaterThanPrecision"); - yield return new TestCaseData(4, 2, true, "+1.23").Returns(true) - .SetName("IsValidNumber_ReturnsTrue_WhenPositiveSymbolWithNumberLengthNotGreaterThanPrecision"); - yield return new TestCaseData(4, 2, false, "-1.23").Returns(true) - .SetName("IsValidNumber_ReturnsTrue_WhenNegativeSymbolWithNumberLengthNotGreaterThanPrecision"); + return new List() + { + new TestCaseData(3, 2, true, "+0.00").Returns(false) + .SetName("False_WhenSymbolWithNumberLengthGreaterThanPrecision"), + + new TestCaseData(3, 2, true, "00.00").Returns(false) + .SetName("False_WhenIntPartWithFracPartGreaterThanPrecision"), + + + new TestCaseData(17, 2, true, "0").Returns(true) + .SetName("True_WhenNumberLengthNotGreaterThanPrecision"), + + new TestCaseData(4, 2, true, "+1.23").Returns(true) + .SetName("True_WhenPositiveSymbolWithNumberLengthNotGreaterThanPrecision"), + + new TestCaseData(4, 2, false, "-1.23").Returns(true) + .SetName("True_WhenNegativeSymbolWithNumberLengthNotGreaterThanPrecision") + }; } } - public static IEnumerable IsValidNumberScaleTests + private static IEnumerable IsValidNumberScaleTests { get { - yield return new TestCaseData(17, 2, true, "0.000").Returns(false) - .SetName("IsValidNumber_ReturnsFalse_WhenFracPartGreaterThanScale"); - yield return new TestCaseData(17, 2, true, "0.0").Returns(true) - .SetName("IsValidNumber_ReturnsTrue_WhenFracPartNotGreaterThanScale"); + return new List() + { + new TestCaseData(17, 2, true, "0.000").Returns(false) + .SetName("False_WhenFracPartGreaterThanScale"), + + new TestCaseData(17, 2, true, "0.0").Returns(true) + .SetName("True_WhenFracPartNotGreaterThanScale") + }; } } - public static IEnumerable IsValidNumberPositivityTests + private static IEnumerable IsValidNumberPositivityTests { get { - yield return new TestCaseData(3, 2, true, "-0.00").Returns(false) - .SetName("IsValidNumber_ReturnsFalse_WhenAcceptsOnlyPositiveButGivenNegativeNumber"); - yield return new TestCaseData(3, 2, false, "-0.0").Returns(true) - .SetName("IsValidNumber_ReturnsTrue_WhenAcceptsAnyAndGivenNegativeNumber"); + return new List() + { + new TestCaseData(3, 2, true, "-0.00").Returns(false) + .SetName("False_WhenAcceptsOnlyPositiveButGivenNegativeNumber"), + + new TestCaseData(3, 2, false, "-0.0").Returns(true) + .SetName("True_WhenAcceptsAnyAndGivenNegativeNumber") + }; } } - public static IEnumerable IsValidNumberSymbolsTests + private static IEnumerable IsValidNumberSymbolsTests { get { - yield return new TestCaseData(3, 2, true, "a.sd").Returns(false) - .SetName("IsValidNumber_ReturnsFalse_WhenGivenNotDigits"); - yield return new TestCaseData(17, 2, true, "").Returns(false) - .SetName("IsValidNumber_ReturnsFalse_WhenEmptyStringGiven"); + return new List() + { + new TestCaseData(3, 2, true, "a.sd").Returns(false).SetName("False_WhenGivenNotDigits"), + + new TestCaseData(17, 2, true, "").Returns(false).SetName("False_WhenEmptyStringGiven") + }; } } - - - public static IEnumerable ConstructorArgumentExceptions + private static IEnumerable ConstructorArgumentExceptions { get { - yield return new TestCaseData(-1,2,true) - .SetName("Constructor_ThrowsArgumentExceptionWhenPercisionNotPositive"); - yield return new TestCaseData(1,2,true) - .SetName("Constructor_ThrowsArgumentExceptionWhenScaleGreaterThanPercision"); - yield return new TestCaseData(1,-1,true) - .SetName("Constructor_ThrowsArgumentExceptionWhenScaleNotPositive"); - yield return new TestCaseData(1,1,true) - .SetName("Constructor_ThrowsArgumentExceptionWhenScaleEqualsPercision"); + return new List() + { + new TestCaseData(-1, 2, true).SetName("WhenPercisionNotPositive"), + + new TestCaseData(1, 2, true).SetName("WhenScaleGreaterThanPercision"), + + new TestCaseData(1, -1, true).SetName("WhenScaleNotPositive"), + + new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPerci sion") + }; } } - [Test, TestCaseSource(nameof(IsValidNumberPositivityTests)), - TestCaseSource(nameof(IsValidNumberPrecisionTests)), - TestCaseSource(nameof(IsValidNumberScaleTests)), - TestCaseSource(nameof(IsValidNumberSymbolsTests))] - public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, string number) - { - return new NumberValidator(precision, scale, onlyPositive).IsValidNumber(number); - } + [TestCaseSource(nameof(IsValidNumberPositivityTests))] + [TestCaseSource(nameof(IsValidNumberPrecisionTests))] + [TestCaseSource(nameof(IsValidNumberScaleTests))] + [TestCaseSource(nameof(IsValidNumberSymbolsTests))] + public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, string number) => + new NumberValidator(precision, scale, onlyPositive).IsValidNumber(number); - [Test, TestCaseSource(nameof(ConstructorArgumentExceptions))] - public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) - { - Invoking(() => new NumberValidator(precision, scale, onlyPositive)).Should().Throw(); - } + + [TestCaseSource(nameof(ConstructorArgumentExceptions))] + public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) => + FluentActions.Invoking(() => new NumberValidator(precision, scale, onlyPositive)) + .Should().Throw(); } public class NumberValidator From dc64fc892a2e48f4c8c819fe5e4e11dd9bdc8bd7 Mon Sep 17 00:00:00 2001 From: daHil Date: Tue, 28 Nov 2023 19:20:04 +0500 Subject: [PATCH 3/6] refactored after feedback 2 --- cs/HomeExercises/NumberValidatorTests.cs | 117 ++++++++--------------- 1 file changed, 40 insertions(+), 77 deletions(-) diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs index 0eaae55a..d6eef2b9 100644 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ b/cs/HomeExercises/NumberValidatorTests.cs @@ -11,86 +11,50 @@ namespace HomeExercises [TestFixture] public class NumberValidatorTests { - private static IEnumerable IsValidNumberPrecisionTests + private static IEnumerable IsValidNumberPrecisionTests = new TestCaseData[] { - get - { - return new List() - { - new TestCaseData(3, 2, true, "+0.00").Returns(false) - .SetName("False_WhenSymbolWithNumberLengthGreaterThanPrecision"), - - new TestCaseData(3, 2, true, "00.00").Returns(false) - .SetName("False_WhenIntPartWithFracPartGreaterThanPrecision"), - - - new TestCaseData(17, 2, true, "0").Returns(true) - .SetName("True_WhenNumberLengthNotGreaterThanPrecision"), - - new TestCaseData(4, 2, true, "+1.23").Returns(true) - .SetName("True_WhenPositiveSymbolWithNumberLengthNotGreaterThanPrecision"), - - new TestCaseData(4, 2, false, "-1.23").Returns(true) - .SetName("True_WhenNegativeSymbolWithNumberLengthNotGreaterThanPrecision") - }; - } - } - private static IEnumerable IsValidNumberScaleTests - { - get - { - return new List() - { - new TestCaseData(17, 2, true, "0.000").Returns(false) - .SetName("False_WhenFracPartGreaterThanScale"), - - new TestCaseData(17, 2, true, "0.0").Returns(true) - .SetName("True_WhenFracPartNotGreaterThanScale") - }; - } - } - private static IEnumerable IsValidNumberPositivityTests + new TestCaseData(3, 2, true, "+0.00").Returns(false) + .SetName("False_WhenSymbolWithNumberLengthGreaterThanPrecision"), + new TestCaseData(3, 2, true, "00.00").Returns(false) + .SetName("False_WhenIntPartWithFracPartGreaterThanPrecision"), + + new TestCaseData(17, 2, true, "0").Returns(true) + .SetName("True_WhenNumberLengthNotGreaterThanPrecision"), + new TestCaseData(4, 2, true, "+1.23").Returns(true) + .SetName("True_WhenPositiveSymbolWithNumberLengthNotGreaterThanPrecision"), + new TestCaseData(4, 2, false, "-1.23").Returns(true) + .SetName("True_WhenNegativeSymbolWithNumberLengthNotGreaterThanPrecision") + }; + + private static IEnumerable IsValidNumberScaleTests = new TestCaseData[] { - get - { - return new List() - { - new TestCaseData(3, 2, true, "-0.00").Returns(false) - .SetName("False_WhenAcceptsOnlyPositiveButGivenNegativeNumber"), - - new TestCaseData(3, 2, false, "-0.0").Returns(true) - .SetName("True_WhenAcceptsAnyAndGivenNegativeNumber") - }; - } - } - private static IEnumerable IsValidNumberSymbolsTests - { - get - { - return new List() - { - new TestCaseData(3, 2, true, "a.sd").Returns(false).SetName("False_WhenGivenNotDigits"), - - new TestCaseData(17, 2, true, "").Returns(false).SetName("False_WhenEmptyStringGiven") - }; - } - } - private static IEnumerable ConstructorArgumentExceptions - { - get - { - return new List() - { - new TestCaseData(-1, 2, true).SetName("WhenPercisionNotPositive"), + new TestCaseData(17, 2, true, "0.000").Returns(false) + .SetName("False_WhenFracPartGreaterThanScale"), + new TestCaseData(17, 2, true, "0.0").Returns(true) + .SetName("True_WhenFracPartNotGreaterThanScale") + }; - new TestCaseData(1, 2, true).SetName("WhenScaleGreaterThanPercision"), + private static IEnumerable IsValidNumberPositivityTests = new TestCaseData[] + { + new TestCaseData(3, 2, true, "-0.00").Returns(false) + .SetName("False_WhenAcceptsOnlyPositiveButGivenNegativeNumber"), + new TestCaseData(3, 2, false, "-0.0").Returns(true) + .SetName("True_WhenAcceptsAnyAndGivenNegativeNumber") + }; - new TestCaseData(1, -1, true).SetName("WhenScaleNotPositive"), + private static IEnumerable IsValidNumberSymbolsTests = new TestCaseData[] + { + new TestCaseData(3, 2, true, "a.sd").Returns(false).SetName("False_WhenGivenNotDigits"), + new TestCaseData(17, 2, true, "").Returns(false).SetName("False_WhenEmptyStringGiven") + }; - new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPerci sion") - }; - } - } + private static IEnumerable ConstructorArgumentExceptions = new TestCaseData[] + { + new TestCaseData(-1, 2, true).SetName("WhenPercisionNotPositive"), + new TestCaseData(1, 2, true).SetName("WhenScaleGreaterThanPercision"), + new TestCaseData(1, -1, true).SetName("WhenScaleNotPositive"), + new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPerci sion") + }; [TestCaseSource(nameof(IsValidNumberPositivityTests))] [TestCaseSource(nameof(IsValidNumberPrecisionTests))] @@ -102,8 +66,7 @@ public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, s [TestCaseSource(nameof(ConstructorArgumentExceptions))] public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) => - FluentActions.Invoking(() => new NumberValidator(precision, scale, onlyPositive)) - .Should().Throw(); + Assert.Throws(() => new NumberValidator(precision, scale, onlyPositive)); } public class NumberValidator From 55a97168d1eeea3ec1cee2c092aeba69897380e6 Mon Sep 17 00:00:00 2001 From: daHil Date: Tue, 28 Nov 2023 19:35:28 +0500 Subject: [PATCH 4/6] refactored after feedback 3 --- cs/HomeExercises/NumberValidatorTests.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs index d6eef2b9..33906167 100644 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ b/cs/HomeExercises/NumberValidatorTests.cs @@ -11,7 +11,7 @@ namespace HomeExercises [TestFixture] public class NumberValidatorTests { - private static IEnumerable IsValidNumberPrecisionTests = new TestCaseData[] + private static IEnumerable IsValidNumberPrecisionTests = new [] { new TestCaseData(3, 2, true, "+0.00").Returns(false) .SetName("False_WhenSymbolWithNumberLengthGreaterThanPrecision"), @@ -26,7 +26,7 @@ public class NumberValidatorTests .SetName("True_WhenNegativeSymbolWithNumberLengthNotGreaterThanPrecision") }; - private static IEnumerable IsValidNumberScaleTests = new TestCaseData[] + private static IEnumerable IsValidNumberScaleTests = new [] { new TestCaseData(17, 2, true, "0.000").Returns(false) .SetName("False_WhenFracPartGreaterThanScale"), @@ -34,7 +34,7 @@ public class NumberValidatorTests .SetName("True_WhenFracPartNotGreaterThanScale") }; - private static IEnumerable IsValidNumberPositivityTests = new TestCaseData[] + private static IEnumerable IsValidNumberPositivityTests = new [] { new TestCaseData(3, 2, true, "-0.00").Returns(false) .SetName("False_WhenAcceptsOnlyPositiveButGivenNegativeNumber"), @@ -42,20 +42,12 @@ public class NumberValidatorTests .SetName("True_WhenAcceptsAnyAndGivenNegativeNumber") }; - private static IEnumerable IsValidNumberSymbolsTests = new TestCaseData[] + private static IEnumerable IsValidNumberSymbolsTests = new [] { new TestCaseData(3, 2, true, "a.sd").Returns(false).SetName("False_WhenGivenNotDigits"), new TestCaseData(17, 2, true, "").Returns(false).SetName("False_WhenEmptyStringGiven") }; - private static IEnumerable ConstructorArgumentExceptions = new TestCaseData[] - { - new TestCaseData(-1, 2, true).SetName("WhenPercisionNotPositive"), - new TestCaseData(1, 2, true).SetName("WhenScaleGreaterThanPercision"), - new TestCaseData(1, -1, true).SetName("WhenScaleNotPositive"), - new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPerci sion") - }; - [TestCaseSource(nameof(IsValidNumberPositivityTests))] [TestCaseSource(nameof(IsValidNumberPrecisionTests))] [TestCaseSource(nameof(IsValidNumberScaleTests))] @@ -64,6 +56,14 @@ public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, s new NumberValidator(precision, scale, onlyPositive).IsValidNumber(number); + private static IEnumerable ConstructorArgumentExceptions = new[] + { + new TestCaseData(-1, 2, true).SetName("WhenPercisionNotPositive"), + new TestCaseData(1, 2, true).SetName("WhenScaleGreaterThanPercision"), + new TestCaseData(1, -1, true).SetName("WhenScaleNotPositive"), + new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPerci sion") + }; + [TestCaseSource(nameof(ConstructorArgumentExceptions))] public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) => Assert.Throws(() => new NumberValidator(precision, scale, onlyPositive)); From b50bce9d4661254072d1436783a68b6e48cdaaa3 Mon Sep 17 00:00:00 2001 From: daHil Date: Wed, 29 Nov 2023 13:39:55 +0500 Subject: [PATCH 5/6] added tests --- cs/HomeExercises/NumberValidatorTests.cs | 56 +++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs index 33906167..6dcba9e6 100644 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ b/cs/HomeExercises/NumberValidatorTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.Contracts; namespace HomeExercises { @@ -34,6 +35,30 @@ public class NumberValidatorTests .SetName("True_WhenFracPartNotGreaterThanScale") }; + private static IEnumerable IsValidNumberBigNumbersTests = new[] + { + new TestCaseData(41, 2, true, $"{Int64.MaxValue}{Int64.MaxValue}").Returns(true) + .SetName("True_WhenGivenBigIntPart"), + new TestCaseData(41, 40, true, $"1,{Int64.MaxValue}{Int64.MaxValue}").Returns(true) + .SetName("True_WhenGivenBigFracPart"), + new TestCaseData(81, 80, true, $"{Int64.MaxValue}{Int64.MaxValue},{Int64.MaxValue}{Int64.MaxValue}") + .Returns(true).SetName("True_WhenGivenBigFractWithIntPart"), + new TestCaseData(1001, 1000, true, $"{1/3}").Returns(true) + .SetName("True_WhenGivenEndlessRationalNumber"), + new TestCaseData(1001, 1000, true, $"{Math.PI}").Returns(true) + .SetName("True_WhenGivenEndlessIrrationalNumber"), + new TestCaseData(2, 1, true, "01").Returns(true) + .SetName("True_WhenGivenNumberInOtherNumberSystemThan10") + }; + + private static IEnumerable IsValidNumberDiffrentFormsOfNumbersTests = new[] + { + new TestCaseData(2, 1, true, "01").Returns(true) + .SetName("True_WhenGivenNumberInOtherNumberSystemThan10"), + new TestCaseData(8, 7, true, "1,23E+10").Returns(false) + .SetName("False_WhenGivenNumberInexponentialForm") + }; + private static IEnumerable IsValidNumberPositivityTests = new [] { new TestCaseData(3, 2, true, "-0.00").Returns(false) @@ -44,14 +69,29 @@ public class NumberValidatorTests private static IEnumerable IsValidNumberSymbolsTests = new [] { + new TestCaseData(3, 2, true, "1,2").Returns(true).SetName("True_WhenSeparatorIsComma"), + + new TestCaseData(3, 2, true, "1;2").Returns(false).SetName("False_WhenSeparatorIsNotCommaOrDot"), + new TestCaseData(3, 2, true, "1.,2").Returns(false).SetName("False_WhenStringContainsMoreThanOneSeparator"), + new TestCaseData(3, 2, true, "\n").Returns(false).SetName("False_WhenGivenSpecialCharacter"), + new TestCaseData(3, 2, true, ",").Returns(false).SetName("False_WhenOnlySeparatorGiven"), + new TestCaseData(3, 2, true, "1a").Returns(false).SetName("False_WhenGivenLetterAfterDigit"), + new TestCaseData(3, 2, true, "a1").Returns(false).SetName("False_WhenGivenDigitAfterLetter"), + new TestCaseData(3, 2, true, null).Returns(false).SetName("False_WhenGivenNull"), new TestCaseData(3, 2, true, "a.sd").Returns(false).SetName("False_WhenGivenNotDigits"), - new TestCaseData(17, 2, true, "").Returns(false).SetName("False_WhenEmptyStringGiven") + new TestCaseData(3, 2, true, "#").Returns(false).SetName("False_WhenGivenNotDigitSymbol"), + new TestCaseData(17, 2, true, "").Returns(false).SetName("False_WhenEmptyStringGiven"), + new TestCaseData(17, 2, true, " ").Returns(false).SetName("False_WhenStringOfSpacesGiven") }; + [Pure] [TestCaseSource(nameof(IsValidNumberPositivityTests))] [TestCaseSource(nameof(IsValidNumberPrecisionTests))] [TestCaseSource(nameof(IsValidNumberScaleTests))] [TestCaseSource(nameof(IsValidNumberSymbolsTests))] + [TestCaseSource(nameof(IsValidNumberDiffrentFormsOfNumbersTests))] + [Repeat(5)] + [TestCaseSource(nameof(IsValidNumberBigNumbersTests))] public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, string number) => new NumberValidator(precision, scale, onlyPositive).IsValidNumber(number); @@ -61,12 +101,24 @@ public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, s new TestCaseData(-1, 2, true).SetName("WhenPercisionNotPositive"), new TestCaseData(1, 2, true).SetName("WhenScaleGreaterThanPercision"), new TestCaseData(1, -1, true).SetName("WhenScaleNotPositive"), - new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPerci sion") + new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPercision") }; + [Pure] [TestCaseSource(nameof(ConstructorArgumentExceptions))] public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) => Assert.Throws(() => new NumberValidator(precision, scale, onlyPositive)); + + [Test] + public void ValidatorState_ShouldStayUnchanged() + { + var validator = new NumberValidator(10, 9, true); + var number = "1,2"; + var resultBeforeChange = validator.IsValidNumber(number); + validator.IsValidNumber("00"); + var resultAfterChange = validator.IsValidNumber(number); + resultAfterChange.Should().Be(resultBeforeChange); + } } public class NumberValidator From 02eaf4621abe8db66eb7b9a3db73720d8daf898e Mon Sep 17 00:00:00 2001 From: daHil Date: Wed, 29 Nov 2023 16:09:18 +0500 Subject: [PATCH 6/6] added tests and refactored --- cs/HomeExercises/NumberValidatorTests.cs | 34 ++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs index 6dcba9e6..48cf1456 100644 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ b/cs/HomeExercises/NumberValidatorTests.cs @@ -35,7 +35,7 @@ public class NumberValidatorTests .SetName("True_WhenFracPartNotGreaterThanScale") }; - private static IEnumerable IsValidNumberBigNumbersTests = new[] + private static IEnumerable IsValidNumberLongNumbersTests = new[] { new TestCaseData(41, 2, true, $"{Int64.MaxValue}{Int64.MaxValue}").Returns(true) .SetName("True_WhenGivenBigIntPart"), @@ -47,16 +47,18 @@ public class NumberValidatorTests .SetName("True_WhenGivenEndlessRationalNumber"), new TestCaseData(1001, 1000, true, $"{Math.PI}").Returns(true) .SetName("True_WhenGivenEndlessIrrationalNumber"), - new TestCaseData(2, 1, true, "01").Returns(true) - .SetName("True_WhenGivenNumberInOtherNumberSystemThan10") }; private static IEnumerable IsValidNumberDiffrentFormsOfNumbersTests = new[] { new TestCaseData(2, 1, true, "01").Returns(true) - .SetName("True_WhenGivenNumberInOtherNumberSystemThan10"), + .SetName("True_WhenGivenNumberInBinaryForm"), + new TestCaseData(2, 1, true, "0001").Returns(false) + .SetName("False_WhenGivenNumberInBinaryFormWithLengthGreaterThanPrecision"), + new TestCaseData(5, 1, true, "8ABCD").Returns(false) + .SetName("False_WhenGivenNumberInHexadecimalFormWithLetters"), new TestCaseData(8, 7, true, "1,23E+10").Returns(false) - .SetName("False_WhenGivenNumberInexponentialForm") + .SetName("False_WhenGivenNumberInExponentialForm") }; private static IEnumerable IsValidNumberPositivityTests = new [] @@ -84,14 +86,13 @@ public class NumberValidatorTests new TestCaseData(17, 2, true, " ").Returns(false).SetName("False_WhenStringOfSpacesGiven") }; - [Pure] - [TestCaseSource(nameof(IsValidNumberPositivityTests))] - [TestCaseSource(nameof(IsValidNumberPrecisionTests))] + [Repeat(5)] [TestCaseSource(nameof(IsValidNumberScaleTests))] [TestCaseSource(nameof(IsValidNumberSymbolsTests))] + [TestCaseSource(nameof(IsValidNumberPrecisionTests))] + [TestCaseSource(nameof(IsValidNumberPositivityTests))] + [TestCaseSource(nameof(IsValidNumberLongNumbersTests))] [TestCaseSource(nameof(IsValidNumberDiffrentFormsOfNumbersTests))] - [Repeat(5)] - [TestCaseSource(nameof(IsValidNumberBigNumbersTests))] public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, string number) => new NumberValidator(precision, scale, onlyPositive).IsValidNumber(number); @@ -104,19 +105,29 @@ public bool IsValidNumber_Returns(int precision, int scale, bool onlyPositive, s new TestCaseData(1, 1, true).SetName("WhenScaleEqualsPercision") }; - [Pure] [TestCaseSource(nameof(ConstructorArgumentExceptions))] public void Constructor_ThrowsArgumentException(int precision, int scale, bool onlyPositive) => Assert.Throws(() => new NumberValidator(precision, scale, onlyPositive)); + private static IEnumerable ConstructorNoExceptions = new[] + { + new TestCaseData(2, 1, true).SetName("WhenPercisionPositiveAndScaleLessThanPrecision") + }; + + [TestCaseSource(nameof(ConstructorNoExceptions))] + public void Constructor_ShouldNotThrowException(int precision, int scale, bool onlyPositive) => + Assert.DoesNotThrow(() => new NumberValidator(precision, scale, onlyPositive)); + [Test] public void ValidatorState_ShouldStayUnchanged() { var validator = new NumberValidator(10, 9, true); var number = "1,2"; + var resultBeforeChange = validator.IsValidNumber(number); validator.IsValidNumber("00"); var resultAfterChange = validator.IsValidNumber(number); + resultAfterChange.Should().Be(resultBeforeChange); } } @@ -140,6 +151,7 @@ public NumberValidator(int precision, int scale = 0, bool onlyPositive = false) numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase); } + [Pure] public bool IsValidNumber(string value) { // Проверяем соответствие входного значения формату N(m,k), в соответствии с правилом,