views:

1276

answers:

4

I am trying to test that a particular method throws an expected exception from a method. As per JUnit4 documentation and this answer I wrote the test as:

@Test(expected=CannotUndoException.class)  
public void testUndoThrowsCannotUndoException() {   
    // code to initialise 'command'

    command.undo();
}

However, this code fails the JUnit test, reporting the thrown (and expected) exception as an error.

The method I'm testing has only this in the body:

public void undo() {
    throw new CannotUndoException();
}

Furthermore, the following test passes:

public void testUndoThrowsCannotUndoException() {
    // code to initialise 'command'

    try { 
        command.undo();
        fail();
    } catch (CannotUndoException cue){

    }
}

Meaning that the expected exception is actually thrown.

I am actually planning to change the method to actually do something, rather than just throw the exception, but it's got me curious as to what caused the problem, lest it should happen again in the future.

The following checks have been made:

  • the CannotUndoException imported into the test case is the correct one
  • version 4 of JUnit is the only one on my classpath
  • a clean and build of Eclipse workspace did not change the outcome

I am using JUnit 4.1, and in the same test I am using Mockito.

What could be causing the erroneous failure?

+3  A: 

Your test code looks ok to me.

Check that you're running with a junit 4 testrunner, not a junit 3.8 testrunner - this could very well be the culprit here (try launching from the command line or just visually inspect the command line when running your test). The classpath of your testrunner may not be the same as your project classpath

This is particularly the case inside IDE's. Alternately you could also try to push to junit 4.4 and see if that solves your problem. (junit 4.5 may cause other problems).

krosenvold
Forgive me for getting a little eclipse-specific... I went to the run configuration of the test in process, and the test runner is marked as JUnit 4. I wonder if they've got mixed up at some point, I now have to worry because it's not the default Eclipse distribution! Thanks.
Grundlefleck
+1 for offering a good insight to the stated question, however, I can't accept the answer as it wasn't the root cause. Thank you :-)
Grundlefleck
A: 

Curious.

I wrote three classes:

An UndoCommand:

public class UndoCommand
{
    public void undo()
    {
        throw new CannotUndoException();
    }
}

A CannotUndoException:

// Note: extends the unchecked superclass RuntimeException
public class CannotUndoException extends RuntimeException
{
    public CannotUndoException()
    {
        super();
    }

    public CannotUndoException(String message)
    {
        super(message);
    }

    public CannotUndoException(String message, Throwable cause)
    {
        super(message, cause);
    }

    public CannotUndoException(Throwable cause)
    {
        super(cause);    
    }
}

And a JUnit 4.4 test class:

import org.junit.Test;

public class UndoCommandTest
{
    @Test(expected=CannotUndoException.class)
    public void testUndo()
    {
        UndoCommand command = new UndoCommand();

        command.undo();
    }
}

Works perfectly - all tests pass, "green" result.

If I remove the (expected=...) from the annotation the test fails, as expected.

I'm using Sun JDK 6, JUnit 4.4 and IntelliJ 7.0.5.

How does yours differ?

duffymo
Code's exactly the same, even the custom exception code.I am running Sun JDK 5, JUnit 4.1 and Eclipse 3.2, however, I think it may be a setting in Eclipse that's did it, as I added the JUnit library today, and probably missed a setting for the test runner, as krosenvold says.
Grundlefleck
Very good. His answer wasn't there when I read your question. It took a minute or two to write, compile, run, and post the code. In that time the other answer appeared.
duffymo
+5  A: 

I have found the problem.

The TestRunner I was using was the correct one (JUnit 4), however, I declared my test class as:

public class CommandTest extends TestCase

Which I assume is causing the test runner to treat it as a JUnit 3 test. I removed extends TestCase and received the expected results.

Grundlefleck
As very often, a case where "show us the code" would have saved some gnashing of teeth :-) Maybe you want to mark the question as answered.
ShiDoiSi
+1  A: 

I had a similar problem and I fixed it by adding the annotation

@RunWith(JUnit4ClassRunner.class)

Which tells the unit tester to run it with the 4er version of Junit

cdecker