tags:

views:

141

answers:

2

So I find myself writing this code all the time:


[TestMethod]
[Description("Asserts that an ArgumentNullException is thrown if ResetPassword(null) is called")]
public void ResetPassword_Throws_ArgumentNullException_With_Null_Parameter( )
{
    try
    {
        new MembershipServiceProvider( ).ResetPassword( null );
    }
    catch ( ArgumentNullException )
    {
        // ArgumentNullException was expected
        Assert.IsTrue( true );
    }
    catch
    {
        Assert.Fail( "ArgumentNullException was expected" );
    }
}

So instead of writing this code over and over I'd really like to create a method which accepts a Lambda expression which will execute the method in the try block.

Something like this:


public void AssertExpectedException( Action theAction ) where TException : Exception
{
    try
    {
        // Execute the method here
    }
    catch ( TException )
    {
        Assert.IsTrue( true );
    }
    catch
    {
        Assert.Fail( string.Format( "An exception of type {0} was expected", typeof( TException ) ) );
    }
}

So I can do something like this:


var provider = new MembershipServiceProvider();
AssertExpectedException(provider => provider.ResetPassword(null));

I'm really not sure if any of this is on the right track but hopefully someone can point me in the right direction.

Thanks

+2  A: 

You're almost there. Here's what the test helper should look like:

public void AssertExpectedException<TException>( Action theAction )
    where TException : Exception 
{ 
    try 
    { 
        // Execute the method here 
        theAction();
    } 
    catch ( TException ) 
    { 
        // The Assert here is not necessary
    } 
    catch 
    { 
        Assert.Fail( string.Format(
            "An exception of type {0} was expected",
            typeof(TException))); 
    } 
} 

And to call it:

var provider = new MembershipServiceProvider(); 
AssertExpectedException<ArgumentNullException>(() => provider.ResetPassword(null)); 

Note the usage of () => something which means the lambda has no parameters. You also have to specify the generic argument of ArgumentNullException because the compiler cannot infer it.

Eilon
+1  A: 

The following should do what you need (I've added the type parameter for TException and the invocation of theAction).

public void AssertExpectedException<TException>(Action theAction) 
    where TException : Exception
{
    try
    {
        theAction();
    }
    catch (TException)
    {
        Assert.IsTrue(true);
    }
    catch
    {
        Assert.Fail(string.Format("An exception of type {0} was expected", 
            typeof(TException)));
    }
}

You can call it with the following code:

var provider = new MembershipServiceProvider();
AssertExpectedException<ArgumentNullException>(() => provider.ResetPassword(null));

You need to specify the type argument to indicate which type of exception to test for. The () => ... syntax is a lambda expression that takes no parameters.

Phil Ross
Perfect! Thanks much.
devlife
How do you execute Action<T> with a parameter?
devlife
@devlife just call it like you would a method with a parameter: `Action<string> theAction = ...;` `theAction("Test");`
Phil Ross
Sorry for the formatting....If I have this:public void AssertExpectedException<TException, T1, T2>(Action<T1, T2> theAction) where TException : Exception{ theAction(); // This doesn't work.}AssertExpectedException<ArgumentNullException, string, int>(a => a.DoSomething("test", 123);theAction() doesn't work. I need to pass in two parameters. How would I do that with the Action<T1, T2> that is passed in?Something like this (although this wouldn't actually work :-) ):theAction( theAction.FirstParameter, theAction.SecondParameter)
devlife
@devlife You don't want to use `Action<T1, T2>`. Leave `AssertExpectedException` as it is in my answer and then call it with `AssertExpectedException<ArgumentNullException>(() => a.DoSomething("test", 123))`. Take a look at http://msdn.microsoft.com/en-us/library/bb397687.aspx for more information about lambda expressions.
Phil Ross