nunit / dotnet-test-nunit

Deprecated test runner for .NET Core. For use with project.json only. For recent releases of .NET Core, use the NUnit 3 Visual Studio Adapter
https://www.nuget.org/packages/dotnet-test-nunit/
MIT License
67 stars 25 forks source link

NUnit catching TargetInvocationException instead of the real exception #74

Closed RTodorov closed 8 years ago

RTodorov commented 8 years ago

framework: netcoreapp1.0 nunit: 3.4.1 dotnet-test-nunit: 3.4.0-beta-2 os: macosx 10.11 (El Capitain)

When asserting for an exception, my test will always fail:

    Expected: <My.System.Exceptions.InsufficientBalanceException>
    But was:  <System.Reflection.TargetInvocationException>

Any exception is being caught as a TargetInvocationException.

I'm not sure if the problem is related to NUnit or the test runner, I'm sorry if this is the wrong place to file this issue!

Thank you!

RTodorov commented 8 years ago

Some extra detail:

2) Failed : My.System.Test.AccountTest.CannotWithdrawFromAccountWithoutBalance
  Expected: <My.System.InsufficientBalanceException>
  But was:  <System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> My.System.InsufficientBalanceException: Exception of type 'My.System.InsufficientBalanceException' was thrown.
   at My.System.Account.Apply(PointsSpent e) in /Users/myuser/Projects/CSHARP/My.System/src/My.System/Account/Account.cs:line 45
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at My.System.PrivateReflectionDynamicObject.InvokeMemberOnType(Type type, Object target, String name, Object[] args) in /Users/myuser/Projects/CSHARP/My.System/src/My.System/PrivateReflectionDynamicObject.cs:line 45
   at My.System.PrivateReflectionDynamicObject.TryInvokeMember(InvokeMemberBinder binder, Object[] args, Object& result) in /Users/myuser/Projects/CSHARP/My.System/src/My.System/PrivateReflectionDynamicObject.cs:line 25
   at CallSite.Target(Closure , CallSite , Object , IEvent )
   at CallSite.Target(Closure , CallSite , Object , IEvent )
   at CallSite.Target(Closure , CallSite , Object , IEvent )
   at My.System.AggregateRoot.ApplyChange(IEvent event, Boolean isNew) in /Users/myuser/Projects/CSHARP/My.System/src/My.System/AggregateRoot.cs:line 51
   at My.System.AggregateRoot.ApplyChange(IEvent event) in /Users/myuser/Projects/CSHARP/My.System/src/My.System/AggregateRoot.cs:line 44
   at My.System.Account.Withdraw(int amount) in /Users/myuser/Projects/CSHARP/My.System/src/My.System/Account/Account.cs:line 25
   at My.System.Test.AccountTest.<>c__DisplayClass6_0.<CannotWithdrawFromAccountWithoutBalance>b__0() in /Users/myuser/Projects/CSHARP/My.System/test/My.System.Tests/AccountTest.cs:line 53
   at NUnit.Framework.Assert.Throws(IResolveConstraint expression, TestDelegate code, String message, Object[] args)>

Assert code:

Assert.Throws<InsufficientBalanceException>(() => account.Withdraw(100));
RTodorov commented 8 years ago

Nevermind, my PrivateReflectionDynamicObject was wrapping the real exception on a TargetInvocationException. My bad!

rprouse commented 8 years ago

Thanks for the update :+1:

CharliePoole commented 8 years ago

It's an interesting issue actually... NUnit calls tests by reflection and when an exception occurs it is almost always seen as a TargetInvocationException. We report the InnerException. But in this case, the InnerException was another TargetInvocationException... perhaps we should show more info about exceptions with inner exceptions once they arrive at the runner level.

RTodorov commented 8 years ago

Well, in case you need more details, the code I'm using came from here:

https://github.com/gautema/CQRSlite/blob/master/Framework/CQRSlite/Infrastructure/PrivateReflectionDynamicObject.cs

The TargetInvocationException was being thrown on this line:

https://github.com/gautema/CQRSlite/blob/master/Framework/CQRSlite/Infrastructure/PrivateReflectionDynamicObject.cs#L46

What I did to "fix" it:

try {
    return member.Invoke(target, args);
} catch (TargetInvocationException ex) {
    throw ex.InnerException;
}
jcansdale commented 8 years ago

Doesn't it already show inner exceptions? I related question is whether it filters stack traces of inner exceptions (e.g. removes Assert stack frames). I know it doesn't with System.AggregateException, so it probably doesn't with inner exceptions either. Should we add this as a feature request?

CharliePoole commented 8 years ago

I mentioned it because I don't know what dotnet-test-nunit does.

NUnit framework would need to be looked at for exceptions that are caught and reported as errors.