views:

287

answers:

4

We've been using NUnit & VisualStudio to write C# .NET code for a while now. Testing Exceptions was done in the style of

old syntax:

[Test]
[ExpectException(typeof(ExceptionType))] 
public void TestExceptionType()
{

}

Now NUnit has released version 2.5.2 which introduced Assert.Throws( Type expectedExceptionType, TestDelegate code ); This makes exception testing a whole lot more flexible. Our exception tests now look like this:

new syntax:

[Test]
public void TestWithNullBufferArgument()
{
   ArgumentNullException ex = Assert.Throws<ArgumentNullException>(() => _testInstance.TestFunction(null));

   // now you can examine the exception and it's properties
   Assert.AreEqual(ex.Message, "Argument was null");
}

Our problem is that if Assert.Throws is used Visual Studio will cough up a window showing an unhandled exception when NUnit (either console or GUI runner) is used to debug the program.

to clarify this: we've set the VS project containing the unit tests to run nunit-x86.exe when debugging. (See project properties, debugging tab, start action is set to run nunit-x86.exe)

This stops NUnit from continuing the tests. It is possible to continue debugging/unit testing by pressing F5 but this is not a viable solution.

Is there any way to avoid this? Putting a try...catch block around the Assert.Throws does nothing since the exception happens in the delegate code.

I hope someone can shed some light on this.

A: 

Could it be achievable by disabling the Exception. Open Debug/Exceptions menu , and search for your Exception.

Bahadir Cambel
This works but it also means that no exceptions will be caught if debugging the real program and not the unit tests. Ideally we'd be looking for a way how to just avoid it when debugging the unit tests. Thanks for the hint, that could be an acceptable solution if nothing else comes up.
Timo Kosig
what if you write two unit tests ? one make sure the exception is thrown , the second will do the execution ?
Bahadir Cambel
I though about that as well. Unfortunately it doesn't work as the exception is thrown by the code in the delegate and Assert.Throws<> is expecting the exception being thrown.
Timo Kosig
+1  A: 

I think you are being blinded by the NUnit assertion. You could achieve the same thing with a simple try/catch.

try
{
  _testInstance.TestFunction(null);
  Assert.Fail("The method should have thrown...");
}catch{}

Now, you have everything you need. You fail if the exception isn't thrown and your regular code can handle exceptions as expected.

Corey Coogan
You are right, this would be a basic way how to handle exceptions in unit test. The beauty of the NUnit exception assert though is that you can test certain properties of the exception which was thrown. For example you can test if the parameter that was passed to the exception was correct. I like and use that and I would like to keep it.
Timo Kosig
Wouldn't you be able to test the exception's parameters this way as well? Rather than catch{} you can say catch(Exception ex) { Assert.IsTrue(ex.Whatever); }
Phil
Yes that is indeed true. Nice and simple, I do like it! My original question though was on the issue the Assert.Throws<> method was causing, therefore I gave the bounty to someone who solved the immediate problem.
Timo Kosig
+1  A: 

The problem itself appears because most likely you have option Enable Just My Code turned on (Tools->Options->Debugging->General->Enable Just My Code).

"When this feature is enabled, the debugger displays and steps into user code ("My Code") only, ignoring system code and other code that is optimized or does not have debugging symbols" (see "General, Debugging, Options Dialog Box")

Normally you have a release version of nunit.framework.dll which does not have a corresponding nunit.framework.pdb file.

So there are 2 options:

  1. Disable "Just My Code" feature

  2. Download sources of nunit (from http://www.nunit.org/index.php?p=download), build them in debug mode, put all nunit.framework.* (dll, pdb, xml) into lib or other directory in your solution and reference that nunit.framework.dll in your test project.

Hope this helps.

dh
dh, this is an interesting line of thought. I tried option 1 (just because it's quick and I haven't had time to try number 2) and unfortunately it didn't make any difference for me. If at all I'm getting more unhandled exceptions now. The issue with Assert.Throws<> causing an unhandled exception is still there.
Timo Kosig
Timo, I'm not completely into your environment but I've tried to reproduce your situation. Here is my set up: [Test] public void Test() { Assert.Throws<Exception>(() => { throw new Exception(); }); }, nunit 2.5.2, run by F5 with external program nunit-console.exe.With enable just my code VS breaks, without succeeds.Is there something else I'm missing?
dh
I don't know. That sounds like my setup except that I'm calling nunit-gui.exe
Timo Kosig
I've tried that for nunit-gui with the same results as for nunit-console. Still there is an option with providing debugging symbols, hope that will work for you.
dh
After looking into it: "Just my code" if you disable that option, VS will not stop on any exceptions. This is not what I intended either. I would like the behaviour of the old `[ExpectException]` syntax where it wouldn't stop on expected exception but it would on ones that weren't expected.
Timo Kosig
@dh, I've tried option 2 and that works. Thanks god! It is a bit of a hack but I'm willing to use this until it works properly with the Release build of NUnit.
Timo Kosig
Glad to here that was helpful for you
dh
+1  A: 

The same problem also annoyed me for quite some time, I did a few tests and found the following:

If a library (nunit in this case) is compiled with debug info set to 'none', then if construct similar to one below is executed withing the library and delegate's code throws an exception, then VS stops complaining about exception not handled by the user code.

Library code:

public static Exception Throws(TestDelegate code, string message)
{
    Exception caughtException = null;

    try
    {
        code();
    }
    catch (Exception ex)
    {
        caughtException = ex;
    }        

    return caughtException;
}

Client code:

private void btnTest_Click(object sender, EventArgs e)
{
  var ex = MyAssert.Throws(() => { throw new Exception(); }, "");    
}

Setting debug info of a library project to any other option other than 'none' resolves the problem i.e. debugger does not stop anymore on those kinda "unhandled" exceptions. I tested it with nunit and my own hand-rolled library with the above code (took a snippet from nunit's Throws method). I suppose it is a feature or a "feature" of VS.

It leaves us with not so many options:

  1. Filter exception as previously suggested

  2. Recompile nunit.framework.dll for local use, to avoid those annoying stops

Other options could be to contact either MS or NUnit teams or both and ask them to investigate/clarify issue and compile NUnit with minimal level of debugging info respectevily.

Edit:

Found one more option.

  1. In my case unchecking 'Suppress JIT optimization on module load' also does the trick, even if libraries compiled with no debug info. However it only works when project is run in release configuration.
dyadenka
dyadenka, thanks a lot for the detailed feedback! Unfortunately dh came up with the same suggestion (recompile nunit framework in debug configuration) a little while ago so he gets the bounty. I've written to the nunit mailing list about this issue as so we'll if they come up with a better solution.
Timo Kosig
No worries, bounty was not aim, primary goal was to solve the problem of those annoying stops in VS.
dyadenka