-
Notifications
You must be signed in to change notification settings - Fork 307
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
Дмитрий Леонтьев #248
base: master
Are you sure you want to change the base?
Дмитрий Леонтьев #248
Conversation
task 1 complete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тэкс, ну раз тема tdd, давай про тесты поговорим).
Давай еще раз поглядим на требования:
Некоторые требования к раскладке:
Форма итогового облака должна быть близка к кругу с центром в точке center. Прямоугольники не должны пересекаться друг с другом. Облако должно быть плотным, чем плотнее, тем лучше.
Надо постараться проверить по требованиям:
- раскладка получается круглой
- центр облака находится в центре
- раскладка плотная, насколько?
- нет пересечений (это у тебя есть)
И добавь тесты на все классы, которые у тебя есть (экстеншны не протестировал)
{ | ||
while (newRectangle.IsNotIntersectOthersRectangles(Rectangles) && desiredPosition != currentPosition) | ||
{ | ||
currentPosition += currentPosition < desiredPosition ? 1 : -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Размазал логику определения того, в какую сторону смещение происходит. Тут считаешь текущую позицию, а реальное направление смещения задано вне этого метода в 32 строке. Надо объединить 2 кусочка в один
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В плане направления смещения логику подсобрал - стало лучше
new(rectangle.Location.X + rectangle.Width / 2, rectangle.Location.Y + rectangle.Height / 2); | ||
|
||
public static bool IsNotIntersectOthersRectangles(this Rectangle rectangle, IEnumerable<Rectangle> rectangles) => | ||
rectangles.All(rect => !rectangle.IntersectsWith(rect)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут можно оптимальнее сделать: если ты уже встретил хотя бы одно пересечение, остальные прямоугольники проверять нет смысла
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
public static Point Add(this Point selfPoint, Point otherPoint) => | ||
new(selfPoint.X + otherPoint.X, selfPoint.Y + otherPoint.Y); | ||
|
||
public static Point Subtract(this Point selfPoint, Point otherPoint) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
класс называется RectangleExtension, а расширение для точки
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
теперь в PointerExtensions лежит расширение для Rectangle)
{ | ||
var newRectangle = MoveRectangleAxis(rectangle, rectangle.GetCenter().X, center.X, | ||
new(rectangle.GetCenter().X < center.X ? 1 : -1, 0)); | ||
newRectangle = MoveRectangleAxis(newRectangle, newRectangle.GetCenter().Y, center.Y, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Интересно будет посмотреть как это выглядит). Подозреваю, что по оси Х плотность будет выше)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Судя по демо рисункам, мои подозрения не оправдались)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
public void GetNextPoint_WithCorrectParameters_ReturnsCorrectPoint() | ||
{ | ||
var spiral = new Spiral(new(0, 0), 1); | ||
spiral.GetNextPoint().Should().Be(new Point(0, 0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Думаю проверку, что первая точка это "центр" можно вынести в отдельный тест
|
||
for (var i = 0; i < countRectangles; i++) | ||
{ | ||
var size = new Size(random.Next(20, 100), random.Next(40, 100)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ну вот, а если бы класс RectangleGenerator был написан удобно, ты бы использовал здесь его)
} | ||
isIntersectsWith.Should().Be(countRectangles); | ||
|
||
rectangles.Clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Зачем очистка, она тут только AAA нарушает. Надо написать так, чтобы тесты не аффектили друг друга.
public void SetUp() | ||
{ | ||
center = new Point(0, 0); | ||
layouter = new CircularCloudLayouter(center); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
При параллельном запуске перетираешь себе данные
|
||
namespace TagsCloudVisualization.CloudLayouter; | ||
|
||
public static class RectangleGenerator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Возможно, этот класс стоит в сборку с тестами унести
|
||
for (var i = 0; i < count; i++) | ||
{ | ||
var size = new Size(random.Next(20,100), random.Next(20, 80)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вроде разброс по высоте меньше, чем по ширине, но все равно может быть такое, что ширина 20, а высота 79. Вряд ли есть слова, у которых высота в 4 раза больше ширины, так что тут алгоритм генерации не совсем соответствует предметной области.
public readonly List<Rectangle> Rectangles = new(); | ||
private readonly Spiral spiral = new(center, 2); | ||
|
||
public Rectangle PutNextRectangle(Size sizeRectangle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Уровень абстракции этого метода какой-то неравномерный. Он часть работы делает сам, часть делегирует.
По красоте оставить бы в нем что-нибудь такое
...
var rectangle = FindNextValidRectanglePosition(sizeRectangle);
rectangle = MoveRectangleCloserToCenter(rectangle);
rectangles.Add(rectangle);
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
add more tests, separate the layouter logic and the GenerateRandomRec…
add task2 and task3
add tests for RectangleDraw
{ | ||
[TestCase(0, 0, 1)] | ||
[TestCase(2, 10, 2)] | ||
public void Constructor_WithCorrectParameters_NotThrow(int x, int y, double step) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А отрицательные аргументы можно?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
можна)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
а вот отрицательный шаг, думаю, что нельзя
return newRectangle; | ||
} | ||
|
||
public void PutRectangles(IEnumerable<Rectangle> rectangles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Старайся соблюдать порядок: сначала все публичные методы, затем все приватные
return newRectangle; | ||
} | ||
|
||
public void PutRectangles(IEnumerable<Rectangle> rectangles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вот это можно унести в Extension метод для ILayouter.
- класс будет чище
- метод можно будет использовать для разных Lyouter-ов (он по природе своей универсальный)
|
||
public class CircularCloudLayouter(Point center) : ILayouter | ||
{ | ||
public readonly List<Rectangle> Rectangles = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Можно лучше инкапсулировать: этот список сейчас доступен для изменения снаружи класса, это не очень хорошо. Вообще, в большинстве случаев, публичные поля это не хорошо, публичные свойства это норм)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Сделал свойство, но инкапсуляция все равно не получилось. Проблема с листом в том, что имея на него ссылку снаружи, можно закидывать в него элементы, удалять, очищать и т. д. Все это снаружи класса не должно быть доступно, нужно оставить только чтение.
На практике так заморачиваются не всегда, но хорошо инкапсулированные коллекции в классе выглядят вот так:
private readonly List<Rectangle> _rectangles = new();
public IReadOnlyList<Rectangle> Rectangles => _rectangles.AsReadOnly();
Здесь внутри класса доступны все операции, а снаружи можно только читать.
Можно еще публиковать коллекцию вот так
public IReadOnlyList<Rectangle> Rectangles => _rectangles
Почти то же самое, но тут мы отдаем объект листа как IReadOnlyList. Снаружи можно будет сделать каст к листу и снова портить инкапсуляцию. А в первом варианте так сделать не получится, потому что возвращатеся объект ReadOnlyCollection у которого кроме чтения методов нет и кастовать к листу уже не получится.
public readonly List<Rectangle> Rectangles = new(); | ||
private readonly Spiral spiral = new(center, 2); | ||
|
||
public Rectangle PutNextRectangle(Size sizeRectangle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
|
||
private static double GetAreaOfCircle(double radius) => Math.PI * Math.Pow(radius, 2); | ||
|
||
private static int GetAreaOfRectangles(CircularCloudLayouter layouter) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Выше у тебя везеде IEnumerable, а тут вдруг layouter. Перечисление лучше
double areaOfCircle, | ||
double averageDistance, | ||
double radius) => | ||
areaOfRectangles / areaOfCircle * (1 - averageDistance / radius); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А первый множитель расчитан неправильно. Перепроверь пожалуйста.
Вообще я посмотрел. У тебя плотность на твоих тестовых данных выше 75% везде. Это хороший результат 🔥
} | ||
|
||
[Test] | ||
public void PutNextRectangle_CheckIntersectRectangles_ReturnFalse() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
плохое название
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PutNextRectangle_CheckIntersectOfRectangles тоже плохо. Название теста всегда должно что-то утверждать о коде.
В данном случае, что пересечений не будет сколько прямоугольников ты бы не положил.
Хорошее название: PutNextRectangle_CreateLayoutWithoutIntersetions
[TestCase(50)] | ||
[TestCase(100)] | ||
[TestCase(1000)] | ||
public void PlacedRectangles_WhenCorrectNotIntersects_ReturnTrue(int countRectangles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
плохое название
[TestCase(-100, 100, 10, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 100, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 1000, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
public void RectanglesDensity_WithDifferentNumberRectanglesAndDifferentCenters( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вот тут как раз не хватает 3й части в названии. Надо что-то типа такого:
PutNextRectangle_CreateLaoyoutWithOver75PercentDencity_OnRandomNumberRectangles
… the logic of the draftsman was divided
add more tests, the tests have been improved, add RectangleExtension,…
} | ||
|
||
[Test] | ||
public void PutNextRectangle_ReturnsFirstRectangleThatIsInCenterOfCloud() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Название хорошее, но не правдивое. Действительно возвращает, действительно в центре, но только когда это первый прямоугольник. Лучше PutNextRectangle_PlaceFirstRectangleAtCenter
[TestCase(50)] | ||
[TestCase(100)] | ||
[TestCase(1000)] | ||
public void PutNextRectangle_CheckIntersectOfRectangles(int countRectangles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Плохое название. Название теста должно утверждать что-то о поведении класса.
return point1.Add(point2); | ||
} | ||
|
||
private static IEnumerable<TestCaseData> PointerSumTestCases() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Потренировался - молодец)
} | ||
|
||
[TestCase(null)] | ||
public void CreateImage_OnInvalidParameters_ThrowsArgumentException(string filename) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ввыкинь тесты на сохранение. Это не ответственность класса, который рисует
public class RectangleGeneratorTest | ||
{ | ||
[Test] | ||
public void GenerateRandomRectangles_CheckNumberRectangles_NumberRectanglesGeneratedMatchesRequested() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Просто утверждение о поведении. CheckNumberRectangles лишнее. Лучше GenerateRandomRectangles_ReturnGeneratedRectanglesNumberMatchesRequested
{ | ||
[TestCase(0, 0, 1)] | ||
[TestCase(2, 10, 2)] | ||
public void Constructor_WithCorrectParameters_NotThrow(int x, int y, double step) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
а вот отрицательный шаг, думаю, что нельзя
namespace TagsCloudVisualizationTests; | ||
|
||
[TestFixture] | ||
public class SpiralTest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В этом классе все имена тестов хорошие
cs/TagsCloudVisualization/Program.cs
Outdated
using TagsCloudVisualization.Extension; | ||
using TagsCloudVisualization.RectangleGenerator; | ||
|
||
var center = new Point(0, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Обсуждали, что лучше бы сделать сборку class library
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В принципе можешь это потом сделать. Сейчас забьем
{ | ||
public static IEnumerable<Rectangle> GenerateRandomRectangles(int countRectangles) | ||
{ | ||
var rectangles = new List<Rectangle>(countRectangles); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Отдаешь IEnumerable, но под капотом держишь list. Можно сделать ленивую генерацию
[TestFixture] | ||
public class CircularCloudLayouterTest | ||
{ | ||
private List<Rectangle> rectanglesForCrashTest = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Надо не забывать во всех тестах писать сюда данные)
- Может возникать проблема при параллельном запуске тестов (ты уже встречался с этим). Для решения этой проблемы можно сделать поле статическим и обернуть его в ThreadLocal. Тогда для каждого потока rectanglesForCrashTest будет свой
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
можно в общем-то забить. Просто отметил на подумать
update tests raundlayout
No description provided.