ThrowsConstraint and Arrange, Act, Assert

50 views
Skip to first unread message

Ian Chamberlain

unread,
Aug 8, 2009, 9:49:17 PM8/8/09
to nunit-...@googlegroups.com

Hi All,

 

I think that the way the ThrowsConstraint requires a delegate mixes the action and assertion parts of the test.

 

Would it not be better to find a way to separate the action from the assertion?

 

Regards

 

Ian Chamberlain

Charlie Poole

unread,
Aug 8, 2009, 10:29:53 PM8/8/09
to nunit-...@googlegroups.com
Hi Ian,
 
Well, a lot of tests do that... For example...
 
Assert.That( 2+2, Is.EqualTo(4));
 
Of course, one can also write
 
int result = 2+2;
Assert.That(result, Is.EqualTo(4));
 
I think it's a matter of style. Personally, I find them both equally well separated. I'll
generally put the action inline if it's a very simple one, because I find that keeping
the thing I'm testing and the test closer together makes it easier to read. But others
may prefer the two-line version.
 
With respect to testing exceptions, the same choices exist. One pattern I use is
to test the type with Assert.Throws<T>() and then make further tests on the
returned exception.
 
I think we should make NUnit usable by folks who want to work in various styles.
 
Charlie


From: nunit-...@googlegroups.com [mailto:nunit-...@googlegroups.com] On Behalf Of Ian Chamberlain
Sent: Saturday, August 08, 2009 6:49 PM
To: nunit-...@googlegroups.com
Subject: [nunit-discuss] ThrowsConstraint and Arrange, Act, Assert

Ian Chamberlain

unread,
Aug 9, 2009, 8:18:50 AM8/9/09
to nunit-...@googlegroups.com

Hi Charlie,

 

I suppose what I’m really looking for is an action syntax that allows an exception to be caught when I expect one, but to cause the test to fail when I don’t.

Maybe it’s more around setting an expectation and then verifying the expectation has been made.

 

Expect<ArgumentNullException>.When(() => new MyClass(null));

Assert.That(Expect.Thrown.ParamName, Is.EqualTo(“argument”));

 

Expect<ApplicationException>.When(() => DoSomething());

Assert.That(Expect.Thrown.InnerException, Is.InstanceOf<ArgumentOutOfRangeException>());

 

Thinking about it this really shouldn’t be that difficult. I’ll try it out and see how it works.

 

Regards

 

Ian

<BR

No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 8.5.392 / Virus Database: 270.13.47/2290 - Release Date: 08/08/09 18:17:00

Fabio Maulo

unread,
Aug 9, 2009, 9:19:34 AM8/9/09
to nunit-...@googlegroups.com
I like
Expect<ArgumentNullException>.When(() => new MyClass(null))

but IMO the assertion about Exception should follow the same sentence

Expect<ArgumentNullException>.When(() => new MyClass(null))
.With(e=> e.ParamName, Is.EqualTo("obj")
.With(e=> e.Message, Is.StringCotains("something"));

Instead of 'With' may be 'And'
Expect<ArgumentNullException>.When(() => new MyClass(null))
.And(e=> e.ParamName, Is.EqualTo("obj")
.And(e=> e.Message, Is.StringCotains("something"));


2009/8/9 Ian Chamberlain <ian.j.ch...@googlemail.com>



--
Fabio Maulo

Charlie Poole

unread,
Aug 9, 2009, 9:59:44 AM8/9/09
to nunit-...@googlegroups.com
This seems to be logically equivalent to
 
ArgumentNullException ex = Assert.Throws<ArgumentNullException>( () => new MyClass(null) );
AssertThat( ex.ParamName, Is.EqualTo("argument"));
 
ApplicationException ex = Assert.Throws<ApplicationException>( () => DoSomething() );
Assert.That( ex.InnerException, Is.InstanceOf<ArgumentOutOfRangeException>() );
 
The above should work... I'm not sure I like the idea of saving the thrown exception from
one statement to use in the next - it seems like too much of a disconnect.
 
My own preference for these examples would be
 
Assert.That( () => new MyClass(null),
                   Throws.TypeOf<ArgumentNullException>.With.ParamName.EqualTo("argument") );
 
Assert.That( ()=> DoSomething(),
                   Throws.InstanceOf<ArgumentOutOfRangeException>() );
 
This will almost work with the current code - you have to replace ParamName by
Property("ParamName") - but we could make ParamName one of the common
exception properties that NUnit has a name for like Message and InnerException.
 
I suspect that we'll be able to generalize this approach to properties if we use
the DLR.
 
Charlie


From: nunit-...@googlegroups.com [mailto:nunit-...@googlegroups.com] On Behalf Of Ian Chamberlain
Sent: Sunday, August 09, 2009 5:19 AM

Ian Chamberlain

unread,
Aug 9, 2009, 10:34:31 AM8/9/09
to nunit-...@googlegroups.com

Hi Fabio,

 

I like to keep the assertion separate from the action.

 

All the Expect is doing is telling the test not to fail if a certain type of exception is thrown and then provide access to the actual exception.

It’s up to the assertion to then establish that the expected result was achieved.

 

At the moment I use a try..catch block and will have different assertions for the exception type, the exception message and for any other properties that may be set on the exception, such as ParamName for ArgumentExceptions.

 

Regards

 

Ian Chamberlain

Charlie Poole

unread,
Aug 9, 2009, 12:52:41 PM8/9/09
to nunit-...@googlegroups.com
Hi Ian,
 
Ah! I had assumed that Expect was the current NUnit Expect which is
basically a synonym for Assert.That and doesn't really give you the
type of separation you're after since it makes the call and validates
the exception type.
 
In any case, I think it could be interesting to explore the various ways
in which people achieve separation of action and assertion. For me,
it doesn't always mean separate statements, since I can create a
sense of the separation by means of the layout of my code.
 
OTOH, you seem to prefer separate statements, with the action
precediing the asserts. If so, you might like to use Catch, which
was previously a public method in NUnit but is now internal. It
is used like this...
 
Exception ex = Catch.Exception( () => DoSomething() );
Assert.That( ex, ....)
 
I wonder if I should make it public again? Or make it part of
the assert class?
 
Charlie


From: nunit-...@googlegroups.com [mailto:nunit-...@googlegroups.com] On Behalf Of Ian Chamberlain
Sent: Sunday, August 09, 2009 7:35 AM

Fabio Maulo

unread,
Aug 9, 2009, 3:23:35 PM8/9/09
to nunit-...@googlegroups.com
Perhaps, instead make public the Catch

var ex = Assert.Throws(Action);
Assert.That(ex.Message.......);

In Assert.Throws(Action) we are checking only that a Exception is throws, without check the type, and returning the exception itself.
The user can then check everything he need about the exception thrown (type, message, cast it and so on).

2009/8/9 Charlie Poole <cha...@nunit.com>



--
Fabio Maulo

Charlie Poole

unread,
Aug 9, 2009, 3:33:01 PM8/9/09
to nunit-...@googlegroups.com
Yes... I'm adding it.
 
Charlie


From: nunit-...@googlegroups.com [mailto:nunit-...@googlegroups.com] On Behalf Of Fabio Maulo
Sent: Sunday, August 09, 2009 12:24 PM
To: nunit-...@googlegroups.com

Charlie Poole

unread,
Aug 9, 2009, 4:23:37 PM8/9/09
to nunit-...@googlegroups.com
Whoops... that doesn't work because of argument resolution errors. I'll have to sit down and
examine all the overloads to see what's happening.
 
Charlie


From: nunit-...@googlegroups.com [mailto:nunit-...@googlegroups.com] On Behalf Of Charlie Poole
Sent: Sunday, August 09, 2009 12:33 PM

Kenneth Xu

unread,
Aug 9, 2009, 4:29:16 PM8/9/09
to nunit-...@googlegroups.com
Hi Charlie,

You don't need that if you are going to add Assert.Catch<T>. We'll then use:

Exception e = Assert.Catch<Exception>(action);

Cheers,
Kenneth

Charlie Poole

unread,
Aug 9, 2009, 9:31:39 PM8/9/09
to nunit-...@googlegroups.com
Hi Kenneth,

It turned out that my problem was related to another change I made
in my local setup.

So, I'm adding several things...
Exception Assert.Throws(del); // Just asserts that an exception was
thrown.
Assert.Catch() // Just gets an exception, if any was
thrown.
Assert.Catch<T> // Same thing, but only catches T

The internal Catch.Exception doesn't do an assert - it returns null if no
exception is thrown. But if it's put under Assert, I think people will
expect it to fail if no exception is thrown or (for Catch<T>) if the
exception is not an instance of T. What do you think?

Charlie

Kenneth Xu

unread,
Aug 9, 2009, 10:10:18 PM8/9/09
to nunit-...@googlegroups.com
Hi Charlie

> But if it's put under Assert, I think people will
> expect it to fail if no exception is thrown or (for Catch<T>) if the
> exception is not an instance of T. What do you think?

I agree! And that's all I need, so I am happy :) Thanks!

BTW, now all three forms below are identical, right?
Assert.Throws() // just my 2 cents: semantics doesn't seem to conform
with it's generic version.
Assert.Catch()
Assert.Catch<Exception>()

Cheers,
Kenneth

Charlie Poole

unread,
Aug 10, 2009, 12:22:49 AM8/10/09
to nunit-...@googlegroups.com
Hi Kenneth,

> > But if it's put under Assert, I think people will expect it
> to fail if
> > no exception is thrown or (for Catch<T>) if the exception is not an
> > instance of T. What do you think?
>
> I agree! And that's all I need, so I am happy :) Thanks!

Great.

> BTW, now all three forms below are identical, right?
> Assert.Throws() // just my 2 cents: semantics doesn't seem to
> conform with it's generic version.
> Assert.Catch()
> Assert.Catch<Exception>()

Yes, all three do the same thing as defined. I guess #2 is completely
superfluous, but Assert.Catch<T> can be used for other types than
just Exception and would apply an InstanceOfType constraint rather than
the ExactTypeConstraint used by Assert.Throws<T>.

Charlie

>
> Cheers,
> Kenneth
>
> >
>



Kenneth Xu

unread,
Aug 10, 2009, 1:40:11 PM8/10/09
to nunit-...@googlegroups.com
Hi Charlie,

I really liked the fact that the name of Throws and Catch matchs
perfectly well with their behaviors. Throws<AException> means I expect
somewhere in my code does "throw new AException()", which should be
exact type. And Catch<AExceptin> analouges to catch(AException), which
is instanceof by nature.

>> BTW, now all three forms below are identical, right?
>> Assert.Throws() // just my 2 cents: semantics doesn't seem to
>> conform with it's generic version.
>> Assert.Catch()
>> Assert.Catch<Exception>()
>
> Yes, all three do the same thing as defined. I guess #2 is completely
> superfluous, but Assert.Catch<T> can be used for other types than
> just Exception and would apply an InstanceOfType constraint rather than
> the ExactTypeConstraint used by Assert.Throws<T>.
>

Yes, Assert.Catch<T> and Assert.Throws<T> are essential as they do
different things. Ideally, Assert.Catch(type, action) would be nice
for 1.x support. Assert.Catch() is superfluous but a nice shortcut for
Assert.Catch<Exception>(action) or Assert.Catch(typeof(Exception),
action).

That being said, I do hold a different view about Assert.Throws(). I
think not only it is superfluous but also it doesn't conform to the
semantics of other Assert.Throws memebers, which *always expect exact
type* of exception.

Cheers,
Kenneth

Charlie Poole

unread,
Aug 10, 2009, 2:32:36 PM8/10/09
to nunit-...@googlegroups.com
Hi Kenneth,

> I really liked the fact that the name of Throws and Catch
> matchs perfectly well with their behaviors.
> Throws<AException> means I expect somewhere in my code does
> "throw new AException()", which should be exact type. And
> Catch<AExceptin> analouges to catch(AException), which is
> instanceof by nature.

Great. I think that analogue for Catch came from Fabio.

> >> BTW, now all three forms below are identical, right?
> >> Assert.Throws() // just my 2 cents: semantics doesn't seem
> to conform
> >> with it's generic version.
> >> Assert.Catch()
> >> Assert.Catch<Exception>()
> >
> > Yes, all three do the same thing as defined. I guess #2 is
> completely
> > superfluous, but Assert.Catch<T> can be used for other
> types than just
> > Exception and would apply an InstanceOfType constraint
> rather than the
> > ExactTypeConstraint used by Assert.Throws<T>.
> >
>
> Yes, Assert.Catch<T> and Assert.Throws<T> are essential as
> they do different things. Ideally, Assert.Catch(type, action)
> would be nice for 1.x support. Assert.Catch() is superfluous
> but a nice shortcut for
> Assert.Catch<Exception>(action) or
> Assert.Catch(typeof(Exception), action).
>
> That being said, I do hold a different view about
> Assert.Throws(). I think not only it is superfluous but also
> it doesn't conform to the semantics of other Assert.Throws
> memebers, which *always expect exact
> type* of exception.

Yes, I saw that it should "logically" be Assert.Catch() if you
consider it as shorthand for Assert.Catch<Exception>(). I only
just added it yesterday, so it could be changed. Let me think
about it a bit.

Charlie

> Cheers,
> Kenneth
>
> >
>



Reply all
Reply to author
Forward
0 new messages