开发者

Checking for 2 expected values in Junit

I have a java program which throws an exception with 2 different messages for 2 different scenarios and I want the Junit test case to check for equality for both of these messages. As an example -

public void amethod() {
           // do some processing
        if(scenario1 == true) {
            throw new MySystemException("An error occured due to case 1 being incorrect.");
        }
        else if(scenario2 == true) {
            throw new MySystemException("An error occured as case 2 could not be found");
        }
    }  

Now the JUnit for this would be something like-

public void testAMethod() {
    // do something
    assertEquals("Expected", "Actual");
}

As I understand, in this above example, if I use the Scenario1 exception message the junit will fail when an exception is thrown for Scenario2 and vice versa.

I would like to know if there is any other way provided in Junit by which I can use this one test method and check for both the messages for the test to pass?

Something like an OR, if possible to provide the "Expected" value with both these expected message.

I hope my query is clear enough.

Thanks

UPDATE

Sorry for the delayed response, had got caught up with some other urgent matter.

Thank you all for the very nice suggestions, it certainly has helped me to understand a bit better now.

Eventually, to keep it rather simple I decided to impl开发者_Go百科ement a somewhat similar solution suggested by Don Roby. So created a new test class which looks like -

public void testAMethodScenario1() {
    // do the necessary
    assertEquals("Expected Exception Message 1", "Actual");
}

public void testAMethodScenario2() {
    // do the necessary
    assertEquals("Expected Exception Message 2", "Actual");
}  

Thank you all again for your responses.


I think you need to manually catch the exception (for each scenario) and individually check the message:

try {
    // trigger scenario 1
    fail("An exception should have been thrown here !");
} catch (MySystemException e1) {
    assertEquals("Wrong error message", m1, e1.getMessage());
}

try {
    // trigger scenario 2
    fail("An exception should have been thrown here !");
} catch (MySystemException e2) {
    assertEquals("Wrong error message", m2, e2.getMessage());
}

Of course, you can have these scenarios defined as enum constants and simply iterate through them and check each of them within a loop, since the "copy/paste design pattern" is pretty obvious in the above code. :)


You seem to be asking two things here, how to test an exception and how to assert that a value matches either of two possible expected values.

To test for an exception, you can either use a JUnit4 annotation:

@Test(expected=MySystemException.class)
public void testException() {
   amethod();
}

or use a try-catch in your test:

@Test
public void testException() {
   try {
      amethod();
      fail("MySystemException expected");
   }
   catch (MySystemException e) {
      // Success!
   }
}

And if you have only one message, in the try-catch version you can assert that you got it with an AssertEquals in the catch block.

The best testing would have separate tests for your two scenarios, and expect the correct single message. Better code might in fact have distinct exceptions for the two situations.

But the need for a more complex assertion than simple equality does come up anyway, and there's an elegant solution for it in Hamcrest matchers.

Using that for this situation, you could write something like (untested - don't trust my syntax completely):

@Test
public void testException() {
   try {
      amethod();
      fail("MySystemException expected");
   }
   catch (MySystemException e) {
      String expectedMessage1 = "An error occured due to case 1 being incorrect.";
      String expectedMessage2 = "An error occured as case 2 could not be found";
      assertThat(e.getMessage(), 
                 anyOf(equalTo(expectedMessage1), equalTo(expectedMessage2)));
   }
}


Can you predict which scenario will occur? If so, Costi's answer is correct. If not, because there's some randomness or whatever, you can write:

@Test
public void testAmethodThrowsException() {
    try {
        amethod();
        fail("amethod() should have thrown an exception");
    }
    catch (MySystemException e) {
        String msg = e.getMessage();
        assertTrue("bad message: " + msg, msg.equals("An error occured due to case 1 being incorrect.") || msg.equals("An error occured as case 2 could not be found"));
    }
}


The declared types of exception thrown bya method are part of its API. If you really want to distinguish different failure modes, you should declare a different exception type for each failure mode.

So, something like this:

/**
 * Do something.
 * @throws MySystemException1 in case 1.
 * @throws MySystemException2 if Foo not found.
 */
public void amethod() {
   // do some processing 
   if(scenario1 == true) {
      throw new MySystemException1("Case 1.");
    }
    else if(scenario2 == true) {
        throw new MySystemException2("Foo not found");
    }
}  


@Rule solution in JUnit4:

    public class ExceptionRule implements MethodRule {
        @Override
        public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        base.evaluate();
                        Assert.fail();
                    } catch (MySystemException e) {
                         if(scenario1)
                            assertEquals("Expected error message1", e1.getMessage();
                         if(scenario2)
                            assertEquals("Expected error message2",e1.getMessage();
                }
            }
        };    
    }
}

In your testcase, use the Rule:

 @Rule public ExceptionRule rule = new ExceptionRule();


JUnit 4 provides (Expected Exception.class)

@Test(expected= MySystemException.class) public void empty() { 
    // what ever you want
}

Google: Expected Exceptions JUnit for more info.


BDD Style Solution with Catch Exception

@Test
public void testAMethodScenario1() {

    //given scenario 1

    when(foo).amethod();

    then(caughtException())
            .isInstanceOf(MySystemException.class)
            .hasMessage("An error occured due to case 1 being incorrect.");
}

@Test
public void testAMethodScenario2() {

    //given scenario 2

    when(foo).amethod();

    then(caughtException())
            .isInstanceOf(MySystemException.class)
            .hasMessage("An error occured as case 2 could not be found");
}

Source code

  • https://gist.github.com/mariuszs/7490875

Dependencies

com.googlecode.catch-exception:catch-exception:1.2.0


A better solution with @Rule, you can assert both exception and expection message as well.

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void aMethod_Scenario1True_ThrowsException() {
    expectedException.expect(MySystemException.class);
    expectedExcepion.expectMessage("An error occured due to case 1 being incorrect.");

    //when().thenReturn(); 
    //handle the repositories, static methods and other sub methods, if needed

    amethod();
}

@Rule is the more elegant way to write the exception.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜