Is there a more appropriate to test if the constructor throws an exception?
Asked Answered
F

3

29

Normally you test, if an exception gets thrown in a certain method, as follows. I use 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>();
}

But how to test, if an exception gets thrown in the constructor? I just did it like this, but is there maybe a more appropriate way via FluentAssertions?

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

    // Act/Assert
    a.ShouldThrow<ArgumentNullException>();
}
Fireman answered 5/6, 2012 at 15:37 Comment(0)
L
27

That's exactly how you're supposed to test for exceptions and that's what ShouldThrow<T>() and ShouldNotThrow<T>() were designed for in the first place. In fact, the Invoking() approach might be marked as obsolete in the next big version (2.0.0).

Linehan answered 5/6, 2012 at 17:31 Comment(8)
But is it the right way to test, if an exception gets thrown in the constructor? Via this action?Fireman
Shame about obsoleting the Invoking() approach. I find it far easier to read than the Action mechanism displayed in the second test above. Invoking keeps everything nicely together so the intent is obvious.Palladium
@ebeen I usually just use the [ExpectedException(typeof(ArgumentNullException))] when testing exceptions being thrown from the constructor. Given that there is only one line in the test, the exception can only be thrown from there.Palladium
@JackHughes The reason why we introduced the Invoking() and ShouldThrow<T>() variants is to get rid of those [ExpectedException] attributes. The Unit Test project for Metro apps doesn't even support that attribute anymore.Linehan
Not a huge fan of [ExpectedException] either... I just prefer it to using the Action syntax from FA in that very specific case. I use FA everywhere else :)Palladium
The Invoking construct is a nice API IMHO BTW :)Palladium
@DennisDoomen - That's Customer Service!! :)Selfdeprecating
We're about to release 2.1, and it's still in ;-)Linehan
L
4

I added a helper method like the below for use when testing constructors:

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

which I then use like this:

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

I know it's a matter of personal taste, but I find this a bit cleaner than needing to declare and assign a delegate first.

This would make the code in the original question look like this:

[Fact]
public void Constructor_throws_Exception()
{    
    // Act/Assert
    Constructor(() => new Foo(null)).ShouldThrow<ArgumentNullException>();
}
Laissezfaire answered 9/3, 2016 at 15:26 Comment(0)
H
4

There's a built-in.

FluentActions.Invoking(() => new Foo(null)).ShouldThrow<ArgumentNullException>();
Huxley answered 31/5, 2021 at 5:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.