Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Большаков Николай #26

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
using NUnit.Framework;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace HomeExercise.Tasks.ObjectComparison;
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));

// Перепишите код на использование 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);
actualTsar.Should().BeEquivalentTo(
expectedTsar,
options => options
.Excluding(member => member.DeclaringType == typeof(Person)
&& member.Name == nameof(Person.Id)));
}

[Test]
Expand All @@ -34,7 +29,18 @@ public void CheckCurrentTsar_WithCustomEquality()
var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70,
new Person("Vasili III of Russia", 28, 170, 60, null));

// Какие недостатки у такого подхода?
// Какие недостатки у такого подхода?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут нужен твой коммент про недостатки AreEqual :)

//
// Решение с FluentAssertions лучше тем, что оно:
// 1. позволяет не изменять проверяющую на равенство часть метода при добавлении новых полей и свойств классу Person.
// Они автоматически будут проверяться.
// Если проверять их не нужно, их можно исключить из проверки, добавив Excluding.
// 2. лучше читается.
// Видно, что объекты сравниваются по всем полям, кроме Id.
// В альтернативном решении нужно искать, какие поля присутствуют в сравнении, а какие - нет.
// 3. работает для каждого типа.
// Альтернативное решение предполагает, что мы должны каждый раз писать новый метод AreEqual.

ClassicAssert.True(AreEqual(actualTsar, expectedTsar));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public NumberValidator(int precision, int scale = 0, bool onlyPositive = false)
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");
throw new ArgumentException("scale must be a non-negative number less than precision");
numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase);
}

Expand Down
257 changes: 234 additions & 23 deletions Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,242 @@

using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace HomeExercise.Tasks.NumberValidator;

[TestFixture]
public class NumberValidatorTests
{
private const string PrecisionOutOfRangeMessage = "precision must be a positive number";
private const string ScaleOutOfRangeMessage = "scale must be a non-negative number less than precision";

[TestCase(0)]
[TestCase(-1)]
[TestCase(int.MinValue)]
[Description("Конструктор бросает исключение, если precision меньше или равен 0")]
public void Constructor_ThrowsException_WhenPrecisionIsNotPositive(
int precision)
{
var constructor = () => new NumberValidator(precision);
constructor.Should().Throw<ArgumentException>().WithMessage(PrecisionOutOfRangeMessage);
}

[TestCase(-1)]
[TestCase(int.MinValue)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а почему minValue проверяем в этих 2-х тестах?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

На случай, если бы в конструкторе с precision и scale выполнялись какие-нибудь операции, которые могут привести к переполнению инта. Например, если бы была проверка "scale > precision - 1"

[Description("Конструктор бросает исключение, если scale отрицателен")]
public void Constructor_ThrowsException_WhenScaleIsNegative(
int scale)
{
var constructor = () => new NumberValidator(1, scale);
constructor.Should().Throw<ArgumentException>().WithMessage(ScaleOutOfRangeMessage);
}

[TestCase(1, 2)]
[TestCase(2, 2)]
[Description("Конструктор бросает исключение, если scale больше или равен precision")]
public void Constructor_ThrowsException_WhenScaleIsGreaterThanOrEqualToPrecision(
int precision,
int scale)
{
var constructor = () => new NumberValidator(precision, scale);
constructor.Should().Throw<ArgumentException>().WithMessage(ScaleOutOfRangeMessage);
}

[TestCase(10, 5)]
[TestCase(10, 0)]
[TestCase(int.MaxValue, int.MaxValue - 1)]
[Description("Нет исключений в конструкторе, если параметры правильные")]
public void Constructor_DoesNotThrowException_WithCorrectParams(
int precision,
int scale)
{
var constructor = () => new NumberValidator(precision, scale);
constructor.Should().NotThrow();
}

[Test]
public void Test()
{
Assert.Throws<ArgumentException>(() => new NumberValidator(-1, 2, true));
Assert.DoesNotThrow(() => new NumberValidator(1, 0, true));
Assert.Throws<ArgumentException>(() => 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"));
}
}
[Description("Scale равен 0, если не указан явно")]
public void Constructor_SetsFractionalPartLengthToZero_ByDefault()
{
var numberValidator = new NumberValidator(10);

numberValidator.IsValidNumber("1").Should().BeTrue();
numberValidator.IsValidNumber("1.1").Should().BeFalse();
}

[Test]
[Description("Работает с отрицательными числами, если в конструкторе не указано обратное")]
public void IsValidNumber_ValidatesNegativeNumbers_IfNotDisabledInConstructor()
{
var numberValidator = new NumberValidator(20, 10);

numberValidator.IsValidNumber("-1").Should().BeTrue();
numberValidator.IsValidNumber("-1.1").Should().BeTrue();
}

[Test, Combinatorial]
[Description("Возвращает true, если строка - удовлетворяющее ограничениям целое число")]
public void IsValidNumber_ReturnsTrue_IfIntegerNumberIsValid(
[Values("", "-", "+")] string sign,
[Values("0", "1", "1234567890", "00", "01")] string number)
{
number = sign + number;
var numberValidator = new NumberValidator(number.Length, 0, false);

numberValidator.IsValidNumber(number).Should().BeTrue();
}

[Test, Combinatorial]
[Description("Возвращает true, если строка - удовлетворяющее ограничениям число с дробной частью")]
public void IsValidNumber_ReturnsTrue_IfNumberWithFractionalPartIsValid(
[Values("", "-", "+")] string sign,
[Values("0", "1", "1234567890", "00", "01")] string intPart,
[Values(".", ",")] string decimalPoint,
[Values("0", "1", "1234567890", "00", "01")] string fracPart)
{
var number = sign + intPart + decimalPoint + fracPart;
var precision = sign.Length + intPart.Length + fracPart.Length;
var numberValidator = new NumberValidator(precision, fracPart.Length, false);

numberValidator.IsValidNumber(number).Should().BeTrue();
}

[TestCase(1, 0, "00")]
[TestCase(3, 2, "00.00")]
[TestCase(1, 0, "11")]
[TestCase(2, 0, "-11")]
[TestCase(2, 1, "-1.1")]
[TestCase(2, 1, "11.1")]
[TestCase(3, 1, "-11.1")]
[Description("Возвращает false, если у числа много знаков в целой части")]
public void IsValidNumber_ReturnsFalse_IfTooManyDigits(
int precision,
int scale,
string number)
{
var numberValidator = new NumberValidator(precision, scale, false);

numberValidator.IsValidNumber(number).Should().BeFalse();
}

[TestCase(2, 0, "0.0")]
[TestCase(3, 1, "0.00")]
[TestCase(2, 0, "1.1")]
[TestCase(3, 1, "1.11")]
[Description("Возвращает false, если у числа много знаков в дробной части")]
public void IsValidNumber_ReturnsFalse_IfTooManyDigitsInFractionalPart(
int precision,
int scale,
string number)
{
var numberValidator = new NumberValidator(precision, scale, false);

numberValidator.IsValidNumber(number).Should().BeFalse();
}

[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
[TestCase(" ")]
[Description("Возвращает false, если строка null или состоит из пробелов")]
public void IsValidNumber_ReturnsFalse_IfStringIsNullOrWhitespace(
string number)
{
var numberValidator = new NumberValidator(10, 9, false);

numberValidator.IsValidNumber(number).Should().BeFalse();
}

[TestCaseSource(nameof(GetNotNumbers))]
[Description("Возвращает false, если строка не является числом")]
public void IsValidNumber_ReturnsFalse_IfNotNumber(
string number)
{
var numberValidator = new NumberValidator(number.Length, number.Length - 1, false);

numberValidator.IsValidNumber(number).Should().BeFalse();
}

[TestCase("-0")]
[TestCase("-1")]
[TestCase("-1.1")]
[Description("Не работает с отрицательными числами, если они отключены")]
public void IsValidNumber_ReturnsFalse_IfNumberIsNegativeAndNegativeNumbersDisabled(
string number)
{
var numberValidator = new NumberValidator(number.Length, number.Length - 1, true);

numberValidator.IsValidNumber(number).Should().BeFalse();
}

[TestCase("0")]
[TestCase("+0")]
[TestCase("1")]
[TestCase("+1")]
[TestCase("1.1")]
[TestCase("+1.1")]
[Description("Работает с положительными числами, если отрицательные отключены")]
public void IsValidNumber_ReturnsTrue_IfNumberIsPositiveAndNegativeNumbersAreDisabled(
string number)
{
var numberValidator = new NumberValidator(number.Length, number.Length - 1, true);

numberValidator.IsValidNumber(number).Should().BeTrue();
}

[Test]
[Description("Работает с большими числами")]
public void IsValidNumber_ReturnsTrue_IfBigIntegerNumberIsValid()
{
var length = 10_000;
var number = new string('1', length);
var numberValidator = new NumberValidator(length, 0, false);

numberValidator.IsValidNumber(number).Should().BeTrue();
}

[Test]
[Description("Работает с числами с большой дробной частью")]
public void IsValidNumber_ReturnsTrue_IfBigNumberWithFractionalPartIsValid()
{
var length = 10_000;
var number = $"0.{new string('1', length - 1)}";

var numberValidator = new NumberValidator(length, length - 1, false);

numberValidator.IsValidNumber(number).Should().BeTrue();
}

[Test]
[Description("Проверка на нескольких валидаторах")]
public void IsValidNumber_Works_WithMultipleNumberValidatorInstances()
{
var number = "111.11";

var numberValidator1 = new NumberValidator(5, 2, false);
var numberValidator2 = new NumberValidator(3, 1, false);

numberValidator1.IsValidNumber(number).Should().BeTrue();
numberValidator2.IsValidNumber(number).Should().BeFalse();
}

private static IEnumerable<TestCaseData> GetNotNumbers()
{
yield return new TestCaseData("abc");
yield return new TestCaseData("123abc");
yield return new TestCaseData("123.abc");
yield return new TestCaseData("abc.123");
yield return new TestCaseData(".");
yield return new TestCaseData(",");
yield return new TestCaseData("1.");
yield return new TestCaseData(".1");
yield return new TestCaseData("--1");
yield return new TestCaseData("++1");
yield return new TestCaseData("1.-1");
yield return new TestCaseData("1.+1");
yield return new TestCaseData("-.1");
yield return new TestCaseData("+.1");
yield return new TestCaseData(" 1");
yield return new TestCaseData("1 ");
yield return new TestCaseData("1. ");
}
}