Skip to content
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
17 changes: 17 additions & 0 deletions Testing/.idea/.idea.Testing/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Testing/.idea/.idea.Testing/.idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Testing/.idea/.idea.Testing/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Testing/.idea/.idea.Testing/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Testing/Advanced/Advanced.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
<PackageReference Include="ApprovalTests" Version="6.0.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
<PackageReference Include="FakeItEasy" Version="8.3.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="log4net" Version="2.0.17" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.22.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="131.0.6778.8700" />
Expand Down
4 changes: 2 additions & 2 deletions Testing/Basic/Basic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.8.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
Expand Down
48 changes: 34 additions & 14 deletions Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,61 @@
using NUnit.Framework;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using FluentAssertions.Equivalency;

namespace HomeExercise.Tasks.ObjectComparison;

public class ObjectComparison
{
[Test]
[Description("Проверка текущего царя")]
[Category("ToRefactor")]
public void CheckCurrentTsar()
public void CurrentTsar_Should_HaveExpectedProperties()
{
var actualTsar = TsarRegistry.GetCurrentTsar();

var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70,

Choose a reason for hiding this comment

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

Для того чтобы понять, хорошо ли новый способ сравнения работает можно было бы написать тесткейсы с разными случаями. Здесь я тебя не прошу этого сделать, но вообще это могло помочь в среднем обнаружить случаи, которые не отсмотрены с текущими проверками. Сейчас в текущем способе проверки есть проблема, попробуй её таким образом воспроизвести.

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);
AreEquivalent(actualTsar, expectedTsar);

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);
//Преимущества такой реализации:
//-тест занимает меньше строк кода,
//-добавление новых свойств не приводит к изменению теста (кроме самой инициализации expectedTsar),
//-добавление вложенных объектов не приводит к изменению теста (кроме самой инициализации expectedTsar),

Choose a reason for hiding this comment

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

А все ли вложенные объекты мы проверим? Советую почитать доку FluentAssertions https://fluentassertions.com/

Copy link
Author

Choose a reason for hiding this comment

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

Нет, проверяются только до 10 уровня вложения, но можно отключить при помощи AllowingInfiniteRecursion
Рекрусия

//-явно указывается несовпадающее свойство.
}

[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));

// Какие недостатки у такого подхода?
ClassicAssert.True(AreEqual(actualTsar, expectedTsar));

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

Choose a reason for hiding this comment

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

Помимо того что метод AreEqual неудобный, есть ли у него какие-то ещё проблемы, из-за которых что-то может пойти не так при работе с ним?

Copy link
Author

Choose a reason for hiding this comment

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

Теоретически при добавлении "родственников" может получится цикл, а значит и бесконечная рекурсия.

Choose a reason for hiding this comment

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

Ну не только это на самом деле прям самый крайний случай. При достаточно большой структуре, которая будет иметь много Parent-ов, мы просто упадём со StackOverflowException т.к. зайдём слишком глубоко.

//-линейный рост количества строк кода при добавлении новых свойств,
//-при добавлении новых свойст в класс их необходимо вносить в метод AreEqual,
//-можно забыть внести проверку совпадения свойств в AreEqual, при этом тест будет выполняться,
//-при падении теста явно не указывается свойство, из-за которого тест падает.
}

private void AreEquivalent(Person actualTsar, Person expectedTsar)
{
actualTsar
.Should()
.BeEquivalentTo(expectedTsar, options =>
options.Excluding(info => IsPersonId(info)));
}

private bool IsPersonId(IMemberInfo info)
{
return info.Name == nameof(Person.Id) &&
info.DeclaringType == typeof(Person);
}

private bool AreEqual(Person? actual, Person? expected)
Expand All @@ -49,4 +69,4 @@ private bool AreEqual(Person? actual, Person? expected)
&& actual.Weight == expected.Weight
&& AreEqual(actual.Parent, expected.Parent);
}
}
}
100 changes: 78 additions & 22 deletions Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,87 @@

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

namespace HomeExercise.Tasks.NumberValidator;

[TestFixture]
public class NumberValidatorTests

Choose a reason for hiding this comment

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

Вообще этот класс можно поделить на несколько. К примеру, разделить тесты на проверку конструктора и конкретного метода, выделив два файла ConstructorTests.cs и IsValidNumberTests.cs. NumberValidator можно упустить в названии файла, потому как по названию папки и так понятно какую сущность тут тестируем. Так будет проще ориентироваться в тестах, но здесь это не критично и скорее будет оверхедом.

{
[Test]
public void Test()
public static IEnumerable<TestCaseData> InvalidConstructorParameters()
{
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"));
var onlyPositiveValues = new[] { true, false };

foreach (var onlyPositive in onlyPositiveValues)
{
yield return new TestCaseData(-1, 2, onlyPositive)
.SetName($"Negative precision should throw (onlyPositive={onlyPositive})");
yield return new TestCaseData(0, 5, onlyPositive)
.SetName($"Zero precision should throw (onlyPositive={onlyPositive})");
yield return new TestCaseData(17, 17, onlyPositive)
.SetName($"Precision equals scale should throw (onlyPositive={onlyPositive})");
yield return new TestCaseData(17, -1, onlyPositive)
.SetName($"Negative scale should throw (onlyPositive={onlyPositive})");
yield return new TestCaseData(17, 18, onlyPositive)
.SetName($"Scale greater than precision should throw (onlyPositive={onlyPositive})");
}
}

[Test, TestCaseSource(nameof(InvalidConstructorParameters))]
public void Constructor_Should_Throw_ArgumentException_When_Invalid_Parameters(int precision, int scale, bool onlyPositive)
{
var action = () => new NumberValidator(precision, scale, onlyPositive);

action.Should().Throw<ArgumentException>();
}

[TestCase(10, 5, true, TestName = "Valid positive number")]
public void Constructor_Should_NotThrow_When_Valid_Parameters(int precision, int scale, bool onlyPositive)
{
var action = () => new NumberValidator(precision, scale, onlyPositive);

action.Should().NotThrow();
}

[TestCase(17, 2, true, "+123.45", TestName = "Valid positive number with plus sign")]
[TestCase(17, 2, false, "-123.45", TestName = "Valid negative number with minus sign")]
[TestCase(17, 2, false, "123,45", TestName = "Valid number with with ',' between integer and scale parts")]
[TestCase(17, 0, true, "123", TestName = "Valid integer without scale part")]
[TestCase(17, 2, true, "0000123.45", TestName = "Valid number with leading zeros")]
[TestCase(17, 2, false, "-0", TestName = "Negative zero with onlyPositive=false")]
[TestCase(2, 0, false, "+0", TestName = "Positive zero with onlyPositive=false")]
public void IsValidNumber_Should_Return_True_When_Valid_Numbers(int precision, int scale, bool onlyPositive, string value)
{
var validator = new NumberValidator(precision, scale, onlyPositive);

var actualResult = validator.IsValidNumber(value);

actualResult.Should().BeTrue();
}

[TestCase(17, 2, true, "1.2.3", TestName = "multiple dots")]
[TestCase(17, 2, true, "--123", TestName = "double minus")]

Choose a reason for hiding this comment

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

Есть проверка на двойной минус, но не на плюс. Почему решил добавить её?

Copy link
Author

Choose a reason for hiding this comment

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

Хотел проверить двойной знак перед числом. Подумал, что с "++" будет повторяющийся тест.

[TestCase(17, 2, true, "++123", TestName = "double plus")]
[TestCase(17, 2, false, "123..45", TestName = "double dots")]
[TestCase(17, 2, true, "12-3", TestName = "minus inside number")]
[TestCase(17, 2, true, "+-123", TestName = "mixed signs")]
[TestCase(17, 2, false, "12a.3", TestName = "Invalid character in number")]
[TestCase(17, 2, false, "\n1.23", TestName = "Special character before")]
[TestCase(17, 2, true, "1234.", TestName = "Trailing dot without fractional part")]
[TestCase(17, 2, false, ".12", TestName = "Leading dot without integer part")]
[TestCase(17, 2, true, "-123", TestName = "Negative number with onlyPositive=true")]

Choose a reason for hiding this comment

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

Тут хорошим тестом видится тест на 0 с разными знаками

[TestCase(17, 0, true, "-0", TestName = "Negative zero with onlyPositive=true")]
[TestCase(1, 0, false, "+0", TestName = "Positive zero with precision 1")]
[TestCase(1, 0, false, "", TestName = "Empty string")]
[TestCase(1, 0, false, null, TestName = "Null string")]
[TestCase(3, 0, false, "a", TestName = "Not a number")]
[TestCase(3, 0, false, " 1", TestName = "Space before the number")]
[TestCase(3, 0, false, "1 ", TestName = "Space after the number")]
[TestCase(3, 0, false, "1 1", TestName = "Space inside the number")]
public void IsValidNumber_Should_Return_False_When_Invalid_Numbers(int precision, int scale, bool onlyPositive, string value)
{
var validator = new NumberValidator(precision, scale, onlyPositive);

var actualResult = validator.IsValidNumber(value);

actualResult.Should().BeFalse();
}
}
16 changes: 16 additions & 0 deletions Testing/Testing.sln.DotSettings.user
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAssertionChain_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc022dff8ceab1a21e3e96b991f8736b3ab0d2a79db4ad60795485d39280_003FAssertionChain_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACompositeWorkItem_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F66eca7339e514aca875e7e128c50570880600_003F25_003F073b6a06_003FCompositeWorkItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALateBoundTestFramework_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff9878f643c2ecf1b4ce73234de56c9754a451c835620eae85ca8babbcb5889c4_003FLateBoundTestFramework_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AObjectAssertions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fcde5ccd369841c3855ce75617c91cb69a307cdd9958f7add3e43fabab82bc6_003FObjectAssertions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWorkItem_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F66eca7339e514aca875e7e128c50570880600_003Fb3_003Fb7fabac5_003FWorkItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=25b42caf_002Debb7_002D49b4_002Db7b5_002Dd35530da5665/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from ObjectComparison.cs" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Project Location="C:\Users\MihailK\Desktop\shpora-testing\Testing\Basic" Presentation="&amp;lt;Basic&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=8aa1bf41_002D3bcb_002D486e_002D96f3_002D3ee4aeed767d/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="Session" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;ProjectFile&gt;6ED454CB-A772-43E5-B72D-3FE9DA27337F/d:Homework/d:1. ObjectComparison/f:ObjectComparison.cs&lt;/ProjectFile&gt;&#xD;
&lt;ProjectFolder&gt;6ED454CB-A772-43E5-B72D-3FE9DA27337F/d:Homework/d:2. NumberValidator&lt;/ProjectFolder&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/SessionState&gt;</s:String>
</wpf:ResourceDictionary>