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

Брозовский Максим #12

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open

Conversation

BMV989
Copy link

@BMV989 BMV989 commented Nov 4, 2024

No description provided.

Copy link

@HELLoWorlD01100 HELLoWorlD01100 left a comment

Choose a reason for hiding this comment

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

У нас все тесты(кроме тестов на конструктор) можно разделить на два вида благодаря тому, что у нас возвращается bool:

  • С валидным значением
  • С невалидным значением

Мб так и поступим, вместо дублирования?

@@ -36,6 +30,9 @@ public void CheckCurrentTsar_WithCustomEquality()

// Какие недостатки у такого подхода?
ClassicAssert.True(AreEqual(actualTsar, expectedTsar));
// Нужно писать сам предикат AreEqual (лишний код в котором можно ошибиться)
// + его надо поддерживать (при расширении класса Person нужно менять логику AreEqual)
// В AreEqual нет Assert, значит при падении теста не будет информации о том как упал тест (причина падения)

Choose a reason for hiding this comment

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

Рассмотри еще кейс, когда у царя поле parent будет указывать на уже встречающегося царя в родословной. Нам же ничего не мешает так сделать :)

Copy link
Author

@BMV989 BMV989 Nov 5, 2024

Choose a reason for hiding this comment

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

Случай несколько вырожден, но формально возможен.
В таком случае возникнет бесконечная рекурсия.
Рассмотрим простой случай: есть actualTsar и пусть actualTsar.Parent.Parent = actualTsar.
Тогда при сравнении AreEqual(actualTsar, actualTsar) мы будем сравнивать их Parent, но у них тоже есть Parent, а значит их мы тоже будем сравнивать и т. д.
Таким образом мы получим бесконечную последовательность вызовов AreEqual для каждого Parent.

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.

А почему вырожден?
Ты не смотри на это как в жизни реально есть, у тебя написан код, который такое допускает.
И т.к мы не можем менять с тобой сурсы, давай обложимся на уровне тестов хотя бы

Copy link
Author

Choose a reason for hiding this comment

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

Окей согласен


namespace HomeExercise.Tasks.NumberValidator;

[TestFixture]
public class NumberValidatorTests
{
[Test]
public void Test()
public void NumberValidator_ThrowsArgumentException_WhenPrecisionIsNegative()

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.

}

[Test]
public void NumberValidator_ThrowsArgumentException_WhenScaleLessThanZero()

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.

}

[Test]
public void NumberValidator_ThrowsArgumentException_WhenScaleLessThanZero()

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.

}

[Test]
public void NumberValidator_ThrowsArgumentException_WhenScaleGreaterOrEqualThanPrecision()

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.

}

[Test]
public void NumberValidator_DoesNotThrow_WhenScaleLessThanPrecision()

Choose a reason for hiding this comment

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

А если работает все только когда разница между ними 1?

Copy link
Author

Choose a reason for hiding this comment

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

[TestCase("-99", 3, false)]
[TestCase("9999999", 7, true)]
[TestCase("-999999999", 10, false)]
public void IsValidNumber_ShouldBeTrue_WhenValueIsInteger(string value, int precision, bool onlyPositive) =>

Choose a reason for hiding this comment

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

А если Int переполнен?

Choose a reason for hiding this comment

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

А если scale тоже позадавать?

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.

Арабские цифры мы проверили, а другие будем проверять?

Copy link
Author

Choose a reason for hiding this comment

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

[TestCase("-300", 3, false)]
[TestCase("300", 2, false)]
[TestCase("-1234567890", 10, false)]
public void IsValidNumber_ShouldBeFalse_WhenValueIsInteger(string value, int precision, bool onlyPositive) =>

Choose a reason for hiding this comment

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

Условие(WhenValueInInteger) должно отражать почему тест работает.
Если я открою тесты и посмотрю почему они упали, я увижу такую картину:

  • IsValidNumber_ShouldBeTrue_WhenValueIsInteger
  • IsValidNumber_ShouldBeFalse_WhenValueIsInteger

Условие одно, результаты разные. Придется лезть явно в код и читать почему тесты падают, из описания я мало что пойму

Copy link
Author

Choose a reason for hiding this comment

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

[TestCase("-1234567890.1234567890", 21, 10, false)]
[TestCase("0.0", 2, 1,false)]
[TestCase("300.52", 5, 2, true)]
public void IsValidNumber_ShouldBeTrue_WhenValueIsFloatNumber(string value, int precision, int scale,

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("+300.52")]
[TestCase("-999.99")]
[TestCase("-101")]
public void IsValidNumber_ShouldBeTrue_WhenValueHasSign(string value) => TestShouldBeTrue(value);

Choose a reason for hiding this comment

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

А мы же отрицательные проверили в кейсаъ IsValidNumber_ShouldBeTrue_WhenValueIsInteger

Copy link
Author

Choose a reason for hiding this comment

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

-- added some edge cases for constructor
-- rework test schema for IsValidNumber
-- added more testcases
@@ -36,6 +30,9 @@ public void CheckCurrentTsar_WithCustomEquality()

// Какие недостатки у такого подхода?
ClassicAssert.True(AreEqual(actualTsar, expectedTsar));
// Нужно писать сам предикат AreEqual (лишний код в котором можно ошибиться)
// + его надо поддерживать (при расширении класса Person нужно менять логику AreEqual)
// В AreEqual нет Assert, значит при падении теста не будет информации о том как упал тест (причина падения)

Choose a reason for hiding this comment

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

А почему вырожден?
Ты не смотри на это как в жизни реально есть, у тебя написан код, который такое допускает.
И т.к мы не можем менять с тобой сурсы, давай обложимся на уровне тестов хотя бы

Comment on lines 13 to 22
[TestCase(-1, 0, PrecisionErrorMessage, Description = "precision < 0")]
[TestCase(-10, 1, PrecisionErrorMessage, Description = "precision < 0")]
[TestCase(0, 0, PrecisionErrorMessage, Description = "precision == 0")]
[TestCase(0, 2, PrecisionErrorMessage, Description = "precision == 0")]
[TestCase(5, -1, ScaleErrorMessage, Description = "scale < 0")]
[TestCase(5, -6, ScaleErrorMessage, Description = "scale < 0")]
[TestCase(1, 2, ScaleErrorMessage, Description = "scale > precision")]
[TestCase(1, 10, ScaleErrorMessage, Description = "scale > precision")]
[TestCase(1, 1, ScaleErrorMessage, Description = "scale == precision")]
[TestCase(2, 2, ScaleErrorMessage, Description = "scale == precision")]

Choose a reason for hiding this comment

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

Там прям TestName вроде есть

Comment on lines 29 to 37
[TestCase(17, 10)]
[TestCase(3, 2)]
[TestCase(1, 0)]
[TestCase(6, 5)]
[TestCase(300, 52)]
public void NumberValidator_DoesNotThrow_WithValidParams(int precision, int scale)
{
Action act = () => new NumberValidator(precision, scale);
act.Should().NotThrow();

Choose a reason for hiding this comment

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

А нам правда важно тестировать валидные аргументы?
Типа, у тебя дофига тестов, которые это уже предполагают и в случае чего, мы поймем на них.

Comment on lines 64 to 96
[TestCase("", 17, 10, false)]
[TestCase(null, 17, 10, false)]
[TestCase("II", 17, 10, false)]
[TestCase("III", 17, 10, false)]
[TestCase("VI", 17, 10, false)]
[TestCase("X", 17, 10, false)]
[TestCase("seven.eleven", 17, 10, false)]
[TestCase("five/two", 17, 10, false)]
[TestCase("11.11.11", 17, 10, false)]
[TestCase("11.22,33", 17, 10, false)]
[TestCase("55,22,33", 17, 10, false)]
[TestCase("1\\2", 17, 10, false)]
[TestCase("-100", 4, 0, true)]
[TestCase("-0.00", 3, 2, true)]
[TestCase("+1,23", 3, 2, true)]
[TestCase("1.123", 4, 2, true)]
[TestCase("0.000", 5, 2, true)]
[TestCase("a.sd", 17, 10, false)]
[TestCase("52", 1, 0, true)]
[TestCase("-300", 3, 0, false)]
[TestCase("300", 2, 0, false)]
[TestCase("-1234567890", 10, 0, false)]
[TestCase("-1.23", 3, 2, false)]
[TestCase("-1234567890.1234567890", 20, 10, false)]
[TestCase("100", 2, 1, true)]
[TestCase("X,Y", 3, 2, true)]
[TestCase("1\n.5", 3, 2, true)]
[TestCase("+-15", 3, 2, false)]
[TestCase("300_000", 17, 10, false)]
[TestCase("52 000", 17, 10, false)]
[TestCase("1/2", 17, 10, false)]
[TestCase("12 . 22", 17, 10, false)]
[TestCase("12 , 22", 17, 10, false)]

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.

Например, кейс [TestCase("-300", 4, 0, false)] из другого тестового метода будет сложно понять по аргументам, придется лезть в реализацию и специфику.

Comment on lines 54 to 55
[TestCase("+1.23", 17, 10, false)]
[TestCase("+3.52", 15, 10, false)]

Choose a reason for hiding this comment

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

А чем эти тесты отличаются?

[TestCase("100", 2, 1, true)]
[TestCase("X,Y", 3, 2, true)]
[TestCase("1\n.5", 3, 2, true)]
[TestCase("+-15", 3, 2, false)]

Choose a reason for hiding this comment

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

А если два одинаковых знака?

Comment on lines 19 to 20
.Excluding(p => p.Id)
.Excluding(p => p.Parent.Id));

Choose a reason for hiding this comment

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

А p.Parent.Parent.Id мы не будем учитывать? :)

Choose a reason for hiding this comment

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

Мы в другом треде говорили про бесконечную рекурсию. А тут какое поведение будет?

Copy link
Author

@BMV989 BMV989 Nov 6, 2024

Choose a reason for hiding this comment

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

В моем старом решение нет, потому что там если будет Parent.Parent, то их Id могут не совпасть и тогда мы упадем с ошибкой что Id не одинаковы (поэтому Id надо исключать у всех), но если их Id и Parent.Id совпадут, то да, будет бесконечная рекурсия

Copy link
Author

Choose a reason for hiding this comment

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

  • Я писал тест исходя из actualTsar и expectedTsar, поэтому я не стал брать рекуретное обобщение

Copy link
Author

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.

но оно не поможет с рекурсией(

Copy link
Author

Choose a reason for hiding this comment

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

оно и не должно, впрочем

Comment on lines 66 to 69
[TestCase("II", 17, 10, false)]
[TestCase("III", 17, 10, false)]
[TestCase("VI", 17, 10, false)]
[TestCase("X", 17, 10, false)]

Choose a reason for hiding this comment

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

Кроме римских есть еще различные цифры, и числа из них, на удивление, будут валидными :)

[TestCase("-1234567890.1234567890", 20, 10, false)]
[TestCase("100", 2, 1, true)]
[TestCase("X,Y", 3, 2, true)]
[TestCase("1\n.5", 3, 2, true)]

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.

Лучше похожие кейсы рядом писать, чтобы контекст постоянно не переключать(например,100 и 300)

[TestCase("55,22,33", 17, 10, false)]
[TestCase("1\\2", 17, 10, false)]
[TestCase("-100", 4, 0, true)]
[TestCase("-0.00", 3, 2, true)]

Choose a reason for hiding this comment

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

Интересный же кейс) Почему положительного кейса нету такого?

Comment on lines 29 to 49
[TestCase("2", 1, 0, true, TestName = "2 should be valid number")]
[TestCase("52", 2, 1, true, TestName = "52 should be valid number")]
[TestCase("-300", 4, 0, false, TestName = "-300 should be valid number")]
[TestCase("+300", 4, 0, true, TestName = "+300 should be valid number")]
[TestCase("-99", 3, 2, false, TestName = "-99 should be valid number")]
[TestCase("9999999", 7, 1, false, TestName = "9999999 should be valid number")]
[TestCase("2147483649", 10, 1, false, TestName = "Int overflow should be valid number")]
[TestCase("-1234567890", 11, 8, false, TestName = "-1234567890 should be valid number")]
[TestCase("0101010", 20, 12, false, TestName = "0101010 should be valid number")]
[TestCase("01110.01010", 10, 5, true, TestName = "01110.01010 should be valid number")]
[TestCase("01110,01010", 10, 5, true, TestName = "01110,01010 should be valid number")]
[TestCase("+01110,01010", 11, 5, true, TestName = "+01110,01010 should be valid number")]
[TestCase("-1234567890.1234567890", 21, 10, false, TestName = "-1234567890.1234567890 should be valid number")]
[TestCase("+0.0", 3, 1, false, TestName = "+0.0 should be valid number")]
[TestCase("0.000", 4, 3, true, TestName = "0.000 should be valid number")]
[TestCase("300.52", 5, 2, true, TestName = "300.52 should be valid number")]
[TestCase("+3.52", 15, 10, false, TestName = "+3.52 should be valid number")]
[TestCase("+300,52", 17, 10, false, TestName = "+300,52 should be valid number")]
[TestCase("1,23", 17, 10, false, TestName = "1,23 should be valid number")]
[TestCase("+100", 4, 1, true, TestName = "+100 should be valid number")]
[TestCase("100\n", 4, 2, true, TestName = "100\n should be valid number")]

Choose a reason for hiding this comment

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

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

Сейчас в случаях, где указаны просто аргументы в TestName'е, как будто нет смысла. Я и так смогу посмотреть аргументы, а мне важен что это за случай.

В случае с 100\n у меня вообще кажется в TestName'е при запуске тестов по итогу будет просто 100?) И как понять что было не так?

Это можно было бы назвать типа: When \n at the end of a number

Comment on lines 55 to 97
[TestCase("", 17, 10, false, TestName = "empty string should be invalid number")]
[TestCase(null, 17, 10, false, TestName = "null should be invalid number")]
[TestCase("II", 17, 10, false, TestName = "II should be invalid number")]
[TestCase("III", 17, 10, false, TestName = "III should be invalid number")]
[TestCase("VI", 17, 10, false, TestName = "VI should be invalid number")]
[TestCase("X", 17, 10, false, TestName = "X should be invalid number")]
[TestCase("ఎనమద", 4, 0 , true, TestName = "ఎనమద should be invalid number")]
[TestCase("తమమద", 4, 0 , true, TestName = "తమమద should be invalid number")]
[TestCase("0xFF", 4, 0, true, TestName = "0xFF should be invalid number")]
[TestCase("0x1A", 4, 0, true, TestName = "0x1A should be invalid number")]
[TestCase("0o75", 4, 0, true, TestName = "0o75 should be invalid number")]
[TestCase("0o44", 4, 0, true, TestName = "0o44 should be invalid number")]
[TestCase("0b1010", 6, 0, true, TestName = "0b1010 should be invalid number")]
[TestCase("0b01110.01010", 10, 5, true, TestName = "0b01110.01010 should be invalid number")]
[TestCase("seven.eleven", 17, 10, false, TestName = "seven.eleven should be invalid number")]
[TestCase("five/two", 17, 10, false, TestName = "five/two should be invalid number")]
[TestCase("11.11.11", 17, 10, false, TestName = "11.11.11 should be invalid number")]
[TestCase("+127.000.001", 17, 10, false, TestName = "+127.000.001 should be invalid number")]
[TestCase("11.22,33", 17, 10, false, TestName = "11.22.33 should be invalid number")]
[TestCase("55,22,33", 17, 10, false, TestName = "55.22.33 should be invalid number")]
[TestCase("+1\\2", 17, 10, false, TestName = "+1\\2 should be invalid number")]
[TestCase("X,Y", 3, 2, true, TestName = "X,Y should be invalid number")]
[TestCase("1\n.5", 3, 2, true, TestName = "1\n.5 should be invalid number")]
[TestCase("\n2.4", 3, 2, true, TestName = "\n2.4 should be invalid number")]
[TestCase("+-15", 3, 2, false, TestName = "+-15 should be invalid number")]
[TestCase("--10", 4, 2, false, TestName = "--10 should be invalid number")]
[TestCase("++1", 3, 0, true, TestName = "++1 should be invalid number")]
[TestCase("300_000", 17, 10, false, TestName = "300_000 should be invalid number")]
[TestCase("52 000", 17, 10, false, TestName = "52 000 should be invalid number")]
[TestCase("1/2", 17, 10, false, TestName = "1/2 should be invalid number")]
[TestCase("12 . 22", 17, 10, false, TestName = "12 . 22 should be invalid number")]
[TestCase("12 , 22", 17, 10, false, TestName = "12 , 22 should be invalid number")]
[TestCase("a.sd", 17, 10, false, TestName = "a.sd should be invalid number")]
[TestCase("-100", 4, 0, true, TestName = "-100 should be invalid number because onlyPositive is true")]
[TestCase("+1,23", 3, 2, true, TestName = "+1.23 should be invalid number because precision < 4")]
[TestCase("1.123", 4, 2, true, TestName = "1.123 should be invalid number because scale < 3")]
[TestCase("0.00", 5, 1, true, TestName = "0.000 should be invalid number because scale < 2")]
[TestCase("52", 1, 0, true, TestName = "52 should be invalid number because precision < 2")]
[TestCase("-300", 3, 0, false, TestName = "-300 should be invalid number because precision < 4")]
[TestCase("300", 2, 0, false, TestName = "300 should be invalid number because precision < 3")]
[TestCase("+100", 3, 0, false, TestName = "+100 should be invalid number because precision < 4")]
[TestCase("-1.23", 3, 2, false, TestName = "-1.23 should be invalid number because precision < 4")]
[TestCase("-1234567890.1234567890", 20, 10, false, TestName = "-1234567890.1234567890 should be invalid number because precision < 21")]

Choose a reason for hiding this comment

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

Тут тоже: мне недостаточно просто знать аргументов, мне важно знать какой сценарий покрывает тест

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants