Pytanie Czy istnieje właściwsze sprawdzenie, czy konstruktor zgłasza wyjątek?


Zwykle testujesz, jeśli wyjątek zostanie rzucony w pewną metodę, w następujący sposób. używam FluentAssertions:

[Fact]
public void Exception_gets_thrown()
{
    // Arrange
    var foo = new Foo("validArgument");

    // Act/Assert
    foo.Invoking(f => f.Bar(null))            // null is an invalid argument
       .ShouldThrow<ArgumentNullException>();
}

Ale jak przetestować, czy wyjątek zostanie wrzucony do konstruktora? Po prostu zrobiłem to w ten sposób, ale czy może jest bardziej odpowiedni sposób przez FluentAssertions?

[Fact]
public void Constructor_throws_Exception()
{
    // Arrange
    Action a = () => new Foo(null);         // null is an invalid argument

    // Act/Assert
    a.ShouldThrow<ArgumentNullException>();
}

16
2018-06-05 15:37


pochodzenie


Nie znam biblioteki, ale lubię to, co zrobiłeś - Paul Phillips


Odpowiedzi:


Dokładnie tak powinieneś testować wyjątki i to właśnie ShouldThrow<T>()  i ShouldNotThrow<T>() zostały zaprojektowane w pierwszej kolejności. W rzeczywistości Invoking() podejście może zostać oznaczone jako przestarzałe w następnej dużej wersji (2.0.0).


13
2018-06-05 17:31



Szkoda, że ​​nie stosujemy metody Invoking (). Uważam, że jest o wiele łatwiejszy do odczytania niż mechanizm Akcji wyświetlany w drugim teście powyżej. Inwokacja utrzymuje wszystko przyjemnie razem, więc intencja jest oczywista. - Jack Hughes
@JackHughes Powodem, dla którego wprowadziliśmy warianty Invoking () i ShouldThrow <T> (), jest pozbycie się atrybutów [ExpectedException]. Projekt Test jednostek dla aplikacji Metro nie obsługuje już tego atrybutu. - Dennis Doomen
Konstrukt Invoking jest miłym API IMHO BTW :) - Jack Hughes
Wtedy go zostawimy. - Dennis Doomen
@DennisDoomen - To obsługa klienta !! :) - Sam


Dodałem metodę pomocniczą, jak poniżej, do użycia podczas testowania konstruktorów:

static Action Constructor<T>(Func<T> func)
{
    return () => func();
}

które następnie używam w ten sposób:

Constructor(() => new Foo("bar", null))
.ShouldThrow<ArgumentNullException>()
.And
.ParamName
.Should()
.Be("baz");

Wiem, że to kwestia osobistego gustu, ale uważam, że jest to trochę czystsze niż konieczność zadeklarowania i przydzielenia delegata jako pierwszego.

To sprawi, że kod w pierwotnym pytaniu będzie wyglądał tak:

[Fact]
public void Constructor_throws_Exception()
{    
    // Act/Assert
    Constructor(() => new Foo(null)).ShouldThrow<ArgumentNullException>();
}

0
2018-03-09 15:26