1

I have a problem with my view-model unit tests. I'd like to test my code like this:

[Test]
public void SelectCommand_ExecutedWithNull_Throws()
{
    // * Arrange
    var fixture = new Fixture();
    var sut = fixture.Build();

    // * Act & Assert
    Assert.Throws<ArgumentNullException>(() => sut.SelectCommand.Execute(null));
}

The action being executed by the command:

private async void Select(IInsuranceCh insurance)
{
    if (insurance == null)
        throw new ArgumentNullException("insurance");

    try
    {
        /* ... */
    }
    catch (Exception err)
    {
        _childWindowService.ShowLoadingErrorWindow(err);
    }
    finally
    {
        IsBusy = false;
    }
}

How I hook up the command:

SelectCommand = new RelayCommand<IInsuranceCh>(Select);

When I try that however, the test fails, even though the exception is thrown and not caught in my code. When i try-catch around the sut.SelectCommand.Execute(null); statement, the catch block isn't entered. This leads me to believe, that the RelayCommand (from MVVM-Light Toolkit) is swallowing up the exception. How can I prevent that?

EDIT: Some clarifications & Assert.Throws

EDIT2: Posted action and command hookup. Maybe the async plays a role?

LueTm
  • 2,366
  • 21
  • 31
  • Not an answer to your question but don't use `ExpectedException` attribute. Instead use `Assert.Throws` or `Assert.That(code, Throws.ArgumentNullException)`. Because test which uses `ExpectedException` could be false positive. It could pass the test even if your fixture setup phase throws the exception not the act phase. – Sriram Sakthivel Mar 30 '15 at 15:58
  • Are you using your RelayCommand or from 3rdParty? – HungDL Mar 30 '15 at 15:59
  • @Neil Yes, I'm using RelayCommand from MVVM-Light. – LueTm Mar 31 '15 at 06:06
  • @SriramSakthivel OK, but the result is the same. – LueTm Mar 31 '15 at 06:07

1 Answers1

1

The reason is: RelayCommand is using reflection to invoke dynamic method. Reflection will wrap action's exception as it internal exception.

When created, the TargetInvocationException is passed a reference to the exception thrown by the method invoked through reflection. The InnerException property holds the underlying exception.
https://msdn.microsoft.com/en-us/library/system.reflection.targetinvocationexception(v=vs.110).aspx

If you want to catch an exception from external library. you must disable 'Just My Code' in debugger's options. (NUnit: Why Doesn't Assert.Throws<T> Catch My ArgumentNullException?)

Community
  • 1
  • 1
HungDL
  • 493
  • 2
  • 11
  • Actually, I **want** to throw an exception. I want to test, that the ArgumentNull exception in my code is thrown. The funny thing is, that my code actually gets executed. And the exception is thrown (tested using the debugger). But the exception gets swallowed. I don't see any try catch in the source code of MVVM-Light though. That's why I'm confused. – LueTm Mar 31 '15 at 08:11
  • The relevant source is here: https://mvvmlight.codeplex.com/SourceControl/latest#GalaSoft.MvvmLight/GalaSoft.MvvmLight%20(PCL)/Command/RelayCommandGeneric.cs – LueTm Mar 31 '15 at 08:15
  • Understood. Command will throw exception if having error inside your action. See my test var command = new RelayCommand( p => { if (p == null) { throw new ArgumentNullException(); } }, p => true); Assert.Throws(() => command.Execute(null)); Can you post your action? – HungDL Mar 31 '15 at 09:02
  • I added the code. Maybe the problem is that my method is async? – LueTm Apr 01 '15 at 06:19
  • I think so, are you sure that your action is executed completely? – HungDL Apr 01 '15 at 06:22
  • It is executed until the `throw` directive... then it returns. I get some 'not in my code' exceptions and then the test method goes on like nothing happens... – LueTm Apr 01 '15 at 06:25
  • Doesn't seem to be an async problem. http://pastebin.com/p5xTVgKT I tested it without async, still the same problem... Again checked that the `throw` gets executed in the debugger. Can you replicate this? – LueTm Apr 01 '15 at 06:30
  • The exception is **swallowed**, not of a different type. I'll have to contact the MVVM light guys directly. They say they love stackoverflow. But they don't really check it :/ – LueTm Apr 01 '15 at 08:09
  • I can reproduce it. Please, see update, Hope last try will be useful to you ^^ – HungDL Apr 01 '15 at 08:52
  • I was so full of hope, but it turned into nope :(. Really seems that the RelayCommand itself is the problem. – LueTm Apr 01 '15 at 09:54