public void CheckCurrentTsar() { Person actualTsar = TsarRegistry.GetCurrentTsar(); Person expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, new Person("Vasili III of Russia", 28, 170, 60, null)); // Перепишите код на использование Fluent Assertions. actualTsar.ShouldBeEquivalentTo(expectedTsar, options => options.Excluding(o => o.SelectedMemberInfo.Name.Equals(nameof(Person.Id))) .ExcludingMissingMembers()); }
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)); // Какие недостатки у такого подхода? // - Нерасширяемый // - Очень много проверок в одном Assert'e // - При фейле не удастся получить конкретную информацию, по какой причине тест упал Assert.True(AreEqual(actualTsar, expectedTsar)); }
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. actualTsar.ShouldBeEquivalentTo(expectedTsar, options => options .Excluding(info => info.SelectedMemberInfo.DeclaringType == typeof(Person) && info.SelectedMemberInfo.Name == nameof(Person.Id))); }
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)); // Какие недостатки у такого подхода? // 1. Если в классе появиться множество полей, значение которых необходимо сравнить, метод разростется до огромных размеров // 2. Если значение поля не удовлетворяет условию, мы не сможем узнать какое это было поле и к какому объекту оно принадлежит. // 3. В теории может быть выброшен StackOverflowException из-за рекурсивной проверки Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Какие недостатки у такого подхода? Assert.True(AreEqual(actualTsar, expectedTsar)); //1.Переписывать метод AreEqual каждый раз при изменении класса(добавлении нового поля/св-ва) Person БОЛЬ //2.FluentAssertions даст однозначно более понятный ответ //3.У BeEquivalentTo есть регулируемое ограничение по глубине, которое позволит избежать циклов }
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)); // Какие недостатки у такого подхода? Assert.True(AreEqual(actualTsar, expectedTsar)); /// Более громоздкое (за счет проверки всех полей в методе AreEqual), /// хуже при расширении, т.е. при добавлении или изменении полей - /// надо будет и AreEqual править. }
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)); actualTsar.Should() .BeEquivalentTo(expectedTsar, options => options.Excluding(info => info.SelectedMemberInfo.DeclaringType.Name == nameof(Person) && info.SelectedMemberInfo.Name.Equals(nameof(Person.Id)))); }
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)); actualTsar.ShouldBeEquivalentTo(expectedTsar, config => config .Excluding(subjectInfo => subjectInfo.SelectedMemberInfo.Name == nameof(Person.Id) && subjectInfo.SelectedMemberInfo.DeclaringType.Name == nameof(Person))); }
public void CheckCurrentTsar_WithCustomEquality() { var actualTsar = TsarRegistry.GetCurrentTsar(); var expectedTsar = new Person("Ivan IV The Terrible", age: 54, height: 170, weight: 70, parent: new Person("Vasili III of Russia", age: 28, height: 146, weight: 60, parent: null)); // Какие недостатки у такого подхода? Assert.True(AreEqual(actualTsar, expectedTsar)); /* Не говорит, в каком месте именно несовпадение (только true или false); * Плохая расширяемость: при добавлении новых полей в Person нужно доопределять AreEqual */ }
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)); actualTsar.Should().BeEquivalentTo(expectedTsar, options => options .Excluding(p => p.SelectedMemberInfo.Name.ToLower() == "id" && p.SelectedMemberInfo.DeclaringType == typeof(Person))); }
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)); // Какие недостатки у такого подхода? // 1) Если мы захотим проверять равенство объектов по еще n критериям, // то придется добавить n проверок. // 2) Не сразу будет ясно, где именно упал тест. Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Какие недостатки у такого подхода? // Изобретаем велосипед, в то время как есть готовые проверенные решения (например, ShouldBeEquivalentTo в FA). // Если в класс Person добавятся новые поля, то нужно будет заодно и переделывать тест, // а если мы забудем его переделать, он не будет учитывать новые поля и может реализовать антипаттерн Liar. Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Какие недостатки у такого подхода? // При добавлении полей/свойств в класс Person, можно забыть их добавить в метод AreEqual. // Когда тест валится, то он не показывает достаточно информации о том, что пошло не так. // При большом количестве атрибутов у класса Person, метод AreEqual будет огромным. Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); actualTsar.ShouldBeEquivalentTo(expectedTsar, options => options.Excluding(o => o.SelectedMemberInfo.DeclaringType == typeof(Person) && o.SelectedMemberInfo.Name == "Id"), "Ivan IV The Terrible is current tsar"); }
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)); actualTsar.ShouldBeEquivalentTo(expectedTsar, assertionOptions => assertionOptions .Excluding(x => x.SelectedMemberInfo.Name == "Parent.Parent") .Excluding(x => x.SelectedMemberPath.EndsWith("Id") && x.SelectedMemberInfo.DeclaringType == typeof(Person))); }
public void CheckCurrentTsar_Fluent() { 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)); void AssertPersonEquals(Person actualPerson, Person expectedPerson) => actualPerson.Should().BeEquivalentTo(expectedPerson, opt => opt.Excluding(x => x.Id).Excluding(x => x.Parent)); AssertPersonEquals(actualTsar, expectedTsar); AssertPersonEquals(actualTsar.Parent, expectedTsar.Parent); }
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)); // Какие недостатки у такого подхода? Assert.True(AreEqual(actualTsar, expectedTsar)); // Главный недостаток в том, что, если что-то сломалось и мы получили false, то мы не узнаем какое значение // и где оно не совпало // Еще один недостаток заключается в том, что при добавлении новых свойств и полей нужно каждый раз // прописывать новую строку в блоке return }
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)); // Какие недостатки у такого подхода? // 1. В сообщении теста не будет говориться о том, какие именно поля не совпали в случае неудачи. // 2. При добавлении новых полей в метод AreEqual придется добавлять новые проверки(или можно переписать с использованием рефлексии). // 3. Немного затрудняет читаемость теста (проверяем, что AreEqual возвращает True вместо того, чтобы сразу проверить объекты на равенство). Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Какие недостатки у такого подхода? Assert.True(AreEqual(actualTsar, expectedTsar)); // если в дереве этих объектов есть цикл, то будет бесконечная рекурсия (в случае с царями этого, конечно, не может быть) // если тест завалится то сложно понять почему, тк он напишет просто expected true и больше никакой инфы // Assert.True не совпадает с семантикой теста // при добавлении/удалении полей из Person рефакторить тест }
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)); // Какие недостатки у такого подхода? // Не понятно, какие именно разлчия у данных объектов. В случае "падения" теста будем знать // только то, что у объектов не совпадают какие-то поля; // При изменении класса Person надо будет дописывать проверки Assert.True(AreEqual(actualTsar, expectedTsar)); }
public void CheckCurrentTsar() { var actualTsar = TsarRegistry.GetCurrentTsar(); var expectedTsar = new Person("Ivan IV The Terrible", age: 54, height: 170, weight: 70, parent: new Person("Vasili III of Russia", age: 28, height: 170, weight: 60, parent: null)); // Перепишите код на использование Fluent Assertions. actualTsar.Should().BeEquivalentTo(expectedTsar, config => config .Excluding(person => person.Id) .Excluding(person => person.Parent.Id)); }
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)); // Какие недостатки у такого подхода? /* если тест провалится, мы не увидим, какие именно поля не соответствуют ожидаемым - придется разглядывать объекты * нужно писать дополнительный метод и менять его каждый раз при изменении объекта */ Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Это решение лучше, тем что оно позволяет понять из-за каких полей повалился тест. // А также выведет все случии на которых тест провалится // Также он менее зависим от текущих полей Person, т.е. при расширении Person нам не нужно будет вносить большие правки в наш тест // Более информативный вывод сообщения при зацикливании родителей сыновей, в нашем решении есть встроенная проверка на циклические ссылки Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Какие недостатки у такого подхода? /* Не понятно какая часть возвращённого объекта неверна * По сути если тест упадёт, то придётся пробегать по нему либо дебаггером, либо глазами, чтобы понять что не так * Может произойти бесконечная рекурсия */ Assert.True(AreEqual(actualTsar, expectedTsar)); }
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, new Person("Basili III of Russia", 28, 170, 60, null))); // Какие недостатки у такого подхода? /* В этом тесте используеться своя реализация AreEqual, поэтому каждый раз * когда будет меняться\добавляться какие-либо поля у класса его нужно будет переделывать * * Еще одна проблема будет, если тест упадет не будет понятна в чем проблема будет просто ожидалось тру, а найденно фалс*/ Assert.True(AreEqual(actualTsar, expectedTsar)); }
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)); // Какие недостатки у такого подхода? // 1. Одна упавшая проверка блокирует прохождение остальных проверок // 2. Плохая читаемость, приходится вникать, чтобы понять, что именно тут проверяется // 3. Неинформативное сообщение при падении теста. // Чтобы понять, где не работает код, нужно изучать traceback, следовательно, тратить больше времени на debug // 4. Плохая расширяемость. Добавление/Удаление свойств класса потребует большое кол-ву изменений в коде Assert.True(AreEqual(actualTsar, expectedTsar)); }
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. actualTsar.ShouldBeEquivalentTo(expectedTsar, options => options .Excluding(si => (si.SelectedMemberInfo.Name == nameof(Person.Id)) && (si.SelectedMemberInfo.DeclaringType == typeof(Person)))); //.Excluding(su => su.SelectedMemberPath.EndsWith("Id"))); // Не знаю какой из них лучше, выбирай :) }
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)); actualTsar.Should().BeEquivalentTo(expectedTsar, opt => setPersonEqOption(opt)); // Раскомментируйте эту строку, чтобы убедиться, что тест не пройдет, если не прописать опции // Если бы менялись глобальные опции, возникали бы нежелательные эффекты в последующих проверках // actualTsar.Should().BeEquivalentTo(expectedTsar); }
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)); // Какие недостатки у такого подхода? Assert.True(AreEqual(actualTsar, expectedTsar)); // Запутанный код, не сразу понятно, что происходит // Также, если не совпадает один из параметров, // то тест упадет и не будет точной информации, где именно ошибка // При добавлении новых полей в класс Person придется каждый раз переписывать тест }
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)); /* * Недостатки: * 1. Такой подход не расширяем. То есть при добавлении новых свойств (полей) * в класс Person необходимо изменить метод AreEqual. * 2. Хуже читаемость по сравнению с Fluent Assertion. */ Assert.True(AreEqual(actualTsar, expectedTsar)); }