FluentAssertions — это альтернативная библиотека утверждений для модульных тестов, которую следует использовать вместо методов в классе Assert, которые предоставляет Microsoft. У него гораздо лучшая поддержка исключений и некоторых других вещей, которые улучшают читаемость и облегчают создание тестов.
Трава зеленее с другой стороны? Попробуйте использовать FluentAssertions вместо простого класса MsTest Assert, и это ПУТЬ лучше.
Кодирование Kentor.AuthServices стало для меня прекрасной возможностью снова сделать настоящий TDD (Test Driven Development). Я долго думал, что [ExpectedException]
атрибута, который предлагает MsTest, недостаточно, поэтому, когда Альбин Суннанбо предложил мне посмотреть на FluentAssertions, я решил попробовать его.
Проверка исключений
FluentAssertions предлагает ShouldThrow()
метод расширения для Action
типа делегата. Он утверждает, что вызов определенного действия вызовет исключение.
// Code from https://github.com/KentorIT/authservices/blob/master/ // Kentor.AuthServices.Tests/Saml2ResponseTests.cs Action a = () => Saml2Response.Read(response).GetClaims(); a.ShouldThrow<InvalidOperationException>() .WithMessage("The Saml2Response must be validated first.");
По сравнению с [ExpectedException]
атрибутом это предлагает намного лучший контроль.
Проблема с [ExpectedException]
Проблема в [ExpectedException]
том, что в нем отсутствует важное свойство: точное указание, где ожидается исключение. Рассмотрим тест, который сначала захватывает подходящий объект для тестирования с помощью LINQ, а затем вызывает исключение.
[TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void Test_Using_ExpectedException() { var attributes = typeof(Brand).GetMember("Nmae").Single() .GetCustomAttributes(false); // This should throw. attributes.OfType<RequiredAttribute>().First() .FormatErrorMessage("InvalidName"); }
При запуске этот тест будет отмечен зеленым, несмотря на опечатку в GetMember
вызове. Проблема в том, что GetMember
выдает InvalidOperationException
метод, который является именно тем, что требуется для прохождения метода. Там нет никакого способа , с , [ExpectedException]
чтобы убедиться , что исключение в нужном месте. Также нет способа проверить более чем одну вещь (например, пост-условие, что объект находится в согласованном состоянии после того, как метод вызвал исключение).
Вместо этого используйте FluentAssertions
С FluentAssertions это намного лучше.
[TestMethod] public void Test_Using_FluentAssertions() { var attributes = typeof(Brand).GetMember("Nmae").Single() .GetCustomAttributes(false); Action a = () => attributes.OfType<RequiredAttribute>().First() .FormatErrorMessage("InvalidName"); a.ShouldThrow<InvalidOperationException>(); }
Код для проверки на исключение теперь помещен в действие. Метод ShouldThrow()
extension выполняет действие и отслеживает исключение. Тест теперь не проходит должным образом, потому что GetMember("Nmae").Single()
выдает исключение, которое не ожидается.
Больше FluentAssertions
Основной синтаксис FluentAssertions заключается в использовании нескольких методов расширения, которые расширяют все. Это еще один пример от Kentor.AuthServices.
// From https://github.com/KentorIT/authservices/blob/master/ // Kentor.AuthServices.Tests/IdentityProviderTests.cs var r = ip.CreateAuthenticateRequest(); r.ToXElement().Attribute("Destination").Should().NotBeNull() .And.Subject.Value.Should().Be(idpUri);
Здесь я могу использовать одну строку, чтобы проверить, что результат ToXElement()
имеет Destination
атрибут и что значение атрибута является правильным.
Лучшее: ShouldBeEquivalentTo
Лучшая часть FluentAssertions ShouldBeEquivalentTo
. В сочетании с анонимными типами это действительно мощный способ тестирования нового метода. Особенно, когда я занимаюсь разработкой на основе тестов, это здорово, потому что я могу скомпилировать и запустить тест еще до того, как коснусь живого кода .
var expected = new { Id = "Saml2Response_Read_BasicParams", IssueInstant = new DateTime(2013, 01, 01, 0, 0, 0, DateTimeKind.Utc), Status = Saml2StatusCode.Requester, Issuer = (string)null }; Saml2Response.Read(response).ShouldBeEquivalentTo(expected);
К сожалению, в API есть недостаток (или я не научился правильно его использовать). ShouldBeEquivalentTo
только проверяет свойства, которые присутствуют в предмете теста, и игнорирует любые дополнительные свойства, найденные в ожидаемом объекте. Я бы предпочел иметь это наоборот. Таким образом, я мог бы ввести новое свойство, начав с добавления его к ожидаемому объекту в тесте.
В реальной жизни, однако, это не большая проблема — просто добавьте новое свойство с return null;
геттером к тестируемому объекту, и тест провалится. Но если бы я мог чего-то пожелать, я бы хотел, чтобы FluentAssertions был расширен с таким поведением, по крайней мере, в качестве настраиваемой опции.
Установка FluentAssertions
Начать работу с FluentAssertions чрезвычайно легко . Просто добавьте пакет FluentAssertions Nuget в проект и затем включите его using FluentAssertions;
в тестовый файл.
Установка FluentAssertions настолько проста, потому что это просто еще один способ написания утверждений теста — он не меняет инфраструктуру теста. Это означает, что тестовый прогон (который может потребовать отдельной установки) не затронут. Это большое преимущество, поскольку необходимость установки отдельных тестовых программ в Visual Studio для нового проекта — это настоящая боль.