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

Рыбин Леонид #17

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
bin/
obj/
.vs/
.vs/
25 changes: 25 additions & 0 deletions Testing/Basic/Basic.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35327.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basic", "Basic.csproj", "{3C8EF388-9BF7-47CF-8B51-CA46F08B9253}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3C8EF388-9BF7-47CF-8B51-CA46F08B9253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C8EF388-9BF7-47CF-8B51-CA46F08B9253}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C8EF388-9BF7-47CF-8B51-CA46F08B9253}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C8EF388-9BF7-47CF-8B51-CA46F08B9253}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {54C706B2-21C4-4C49-A162-2E765ACC0F80}
EndGlobalSection
EndGlobal

This comment was marked as off-topic.

This comment was marked as off-topic.

Copy link
Author

Choose a reason for hiding this comment

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

Да, вроде бы. Я помню он мне файл .sln предложил сохранить.

9 changes: 9 additions & 0 deletions Testing/Basic/Basic.sln.DotSettings.user
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<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/Environment/UnitTesting/UnitTestSessionStore/Sessions/=ac147a29_002D1949_002D44a0_002D9289_002Dab17f1aa8756/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests in category 'ToRefactor'" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Category&gt;ToRefactor&lt;/Category&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;NUnit3x::3C8EF388-9BF7-47CF-8B51-CA46F08B9253::net8.0::HomeExercise.Tasks.NumberValidator.NumberValidatorTests&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>

This comment was marked as off-topic.

Copy link
Author

Choose a reason for hiding this comment

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

Я погуглил и вроде как файл DotSettings.user добавляют в .gitignore. Это обязательно ?

Choose a reason for hiding this comment

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

В DotSettings.user обычно какие-то локальные настройки хранятся, скорее всего он создался из-за того что появился солюшен. В данном случае, да - его логично заигнорить.

В следующей домашке попробуй без солюшена редактировать проект, скорее всего такой проблемы просто не возникнет.

27 changes: 16 additions & 11 deletions Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NUnit.Framework;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace HomeExercise.Tasks.ObjectComparison;
Expand All @@ -14,16 +15,8 @@ public void CheckCurrentTsar()
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(o => o.Name == nameof(Person.Id) && o.DeclaringType == typeof(Person)));
}

[Test]
Expand All @@ -35,6 +28,18 @@ public void CheckCurrentTsar_WithCustomEquality()
new Person("Vasili III of Russia", 28, 170, 60, null));

// Какие недостатки у такого подхода?
/*
1) Метод AreEqual проверяет только фиксированые параметры в Person, поэтому
если класс Person будет измненён, то тесты предётся переписывать,
добавляя новые или удаляя старые поля.
2) Метод AreEqual возвращает True или False, поэтому даже если только одно поле
не пройдёт проверку, всё что будет понятно, что проверка не прошла, а
что именно было не так, узнать не получится.
3) Даже если переписывание тестов не является проблемой (см. 1)), то при добавлении
большего количества полей, особенно если типом новых полей будут другие классы
со своими полями, метод AreEqual рискует разрастись до монструозных масштабов,
из-за чего его станет очень сложно читать.
*/
ClassicAssert.True(AreEqual(actualTsar, expectedTsar));
}

Expand Down
81 changes: 60 additions & 21 deletions Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,70 @@

using System.Collections;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace HomeExercise.Tasks.NumberValidator;

[TestFixture]
public class NumberValidatorTests
{
[Test]
public void Test()
[TestCase(-1, 2, true, TestName = "Negative precision throws exception")]
[TestCase(0, 2, false, TestName = "Precision equals 0 throws exception")]
[TestCase(1, -2, true, TestName = "Negative scale throws exception")]
[TestCase(1, 2, false, TestName = "Scale greater than precision throws exception")]
[TestCase(1, 1, true, TestName = "Scale equals precision throws exception")]
public void NumberValidation_ConstructorThrowsArgumentException(int precision, int scale, bool onlyPositive)

Choose a reason for hiding this comment

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

Тут всё хорошо, править не будем, но на будущее:
Здесь наименование метода уже говорит нам о действии и об ожиданиях, поэтому в тест-кейсах необязательно прописывать "NumberValidator_" и "_ThrowsException".

Сейчас теряются из вида условия, когда должна быть вкинута ошибка:
image

Choose a reason for hiding this comment

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

И вот как можно сделать:
У меня информация о том, что проверятся и что ожидается есть - она взята из наименования тест-метода
Все тест-кейсы объединились в группу этого тест-метода, и я точно и чётко вижу все условия, когда конструктор должен упасть с ошибкой
image

{
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 action = () => new NumberValidator(precision, scale, onlyPositive);

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

This comment was marked as resolved.

}

[Test(Description = "Creating an instance of a class with the correct parameters should not throw an exception")]
public void NumberValidation_ConstructorDoesNotHaveArgumentException()
{
var action = () => new NumberValidator(1, 0, true);

action.Should().NotThrow();
}

[TestCaseSource(nameof(TestCase1))]
[TestCaseSource(nameof(TestCase2))]
public bool IsValidNumber_WorksCorrectly(int precision, int scale, bool onlyPositive, string value)
{
return new NumberValidator(precision, scale, onlyPositive).IsValidNumber(value);
}

public static IEnumerable TestCase1

Choose a reason for hiding this comment

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

Ну давай уж осмысленно назовем: ValidNumbersCases и InvalidNumbersCases
Можно даже ещё отдельно выделить InvalidInputCases и туда разместить тесты с некорректным инпутом: пустая строка, нет целой части у Decimal и прочие

{
get
{
yield return new TestCaseData(1, 0, true, "0").SetName("Validation of zero with the correct parameters should be completed successfully").Returns(true);
yield return new TestCaseData(2, 1, true, "0.0").SetName("Validation of zero with a zero fractional part separated by a dot with the correct parameters should be completed successfully").Returns(true);
yield return new TestCaseData(2, 1, true, "0.1").SetName("Validation of zero with a non-zero fractional part separated by a dot with correct parameters should be completed successfully").Returns(true);
yield return new TestCaseData(2, 1, true, "0,1").SetName("Validation of zero with a non-zero decimal part separated by a comma with correct parameters should be completed successfully").Returns(true);
yield return new TestCaseData(2, 0, true, "+1").SetName("Validation of a positive integer with an explicit plus sign with correct parameters should be completed successfully").Returns(true);
yield return new TestCaseData(3, 1, true, "+1.1").SetName("Validation of a positive number with a non-zero fractional part separated by a dot and an explicit plus sign with the correct parameters must be completed successfully").Returns(true);
yield return new TestCaseData(3, 1, true, "+1,1").SetName("Validation of a positive number with a non-zero fractional part separated by a comma and an explicit plus sign with the correct parameters must be completed successfully").Returns(true);
yield return new TestCaseData(2, 0, false, "-1").SetName("Validation of a negative integer with an explicit minus sign with correct parameters should be completed successfully").Returns(true);
yield return new TestCaseData(3, 1, false, "-1.1").SetName("Validation of a negative number with a non-zero fractional part separated by a dot and an explicit minus sign with the correct parameters must be completed successfully").Returns(true);
yield return new TestCaseData(3, 1, false, "-1,1").SetName("Validation of a negative number with a non-zero fractional part separated by a comma and an explicit minus sign with the correct parameters must be completed successfully").Returns(true);
yield return new TestCaseData(7, 2, true, "671,23").SetName("Validation a real number with a non-zero fractional part separated by a comma with the correct parameters must be completed successfully").Returns(true);
}
}

public static IEnumerable TestCase2
{
get
{
yield return new TestCaseData(2, 0, true, "").SetName("Empty string is not allowed").Returns(false);
yield return new TestCaseData(2, 1, true, ".0").SetName("Integer part of a real number must be").Returns(false);
yield return new TestCaseData(2, 0, true, "0.").SetName("Fractional part of a real number must be if a separator character is used").Returns(false);
yield return new TestCaseData(2, 0, true, "-1").SetName("If a minus is explicitly specified, onlyPositive must be false").Returns(false);
yield return new TestCaseData(10, 2, true, "abcde.f").SetName("Use only digits").Returns(false);
yield return new TestCaseData(10, 9, true, "127.0.0.1").SetName("Only real numbers format").Returns(false);
yield return new TestCaseData(3, 2, true, "4321.5").SetName("If precision is less than number of digits in the number, return false").Returns(false);
yield return new TestCaseData(3, 0, true, "+145").SetName("If a plus is explicitly specified, it must be taken into account when calculating precision").Returns(false);
yield return new TestCaseData(3, 0, false, "-124").SetName("If a minus is explicitly specified, it must be taken into account when calculating precision").Returns(false);
}

This comment was marked as resolved.

Copy link
Author

Choose a reason for hiding this comment

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

Я переписал название тестов в развернутом виде, но PascalCase требует каждое слово с большой буквы писать, но в названии теста там предложение обычное, и как-то не очень в предложении каждое слово с большой буквы писать.

This comment was marked as resolved.

This comment was marked as resolved.

}
}