Monday, November 19, 2007

How to call EasyMock.verify() when you expect an exception in TestNG

I have this test which is written in JUnit
public void testConvertWithUnknownCurrency()
throws UnknownCurrencyException {
EasyMock.expect(
exchangeRateService.getExchangeRate(
EasyMock.isA(String.class),
EasyMock.isA(String.class)
)
).andThrow(new UnknownCurrencyException());

EasyMock.replay(exchangeRateService);

try {
converter.convert(10.0, "EUR", "-UNKNOWN-");
fail("an unknown currency exception was expected");
} catch (UnknownCurrencyException e) {
// do nothing, was expected
}

EasyMock.verify(exchangeRateService);
}

I converted it to use TestNG as below
@Test(expectedExceptions = {UnknownCurrencyException.class})
public void testConvertWithUnknownCurrency() {
EasyMock.expect(
exchangeRateService.getExchangeRate(
EasyMock.isA(String.class),
EasyMock.isA(String.class)
)
).andThrow(new UnknownCurrencyException());

EasyMock.replay(exchangeRateService);

converter.convert(10.0, "EUR", "-UNKNOWN-");

EasyMock.verify(exchangeRateService);
}

then found that EasyMock.verify(exchangeRateService) will never be called 'cause converter.convert(10.0, "EUR", "-UNKNOWN-") throws UnknownCurrencyException. So how to make the test works as same as JUnit version?

Spend more time to read TestNG document and search in TestNG forum, I found that I can use @Test's dependsOnMethods attribute. But note that TestNG supports 2 kinds of dependencies: hard and soft. And here is explaination from TestNG document:

* Hard dependencies. All the methods you depend on must have run and succeeded for you to run. If at least one failure occurred in your dependencies, you will not be invoked and marked as a SKIP in the report.
* Soft dependencies. You will always be run after the methods you depend on, even if some of them have failed. This is useful when you just want to make sure that your test methods are run in a certain order but their success doesn't really depend on the success of others. A soft dependency is obtained by adding "alwaysRun=true" in your @Test annotation.

Now I have a clear understanding about dependsOnMethods, what I need is a soft dependency. And here is TestNG version of above test.
@Test(expectedExceptions = {UnknownCurrencyException.class})
public void testConvertWithUnknownCurrency() {
EasyMock.expect(
exchangeRateService.getExchangeRate(
EasyMock.isA(String.class),
EasyMock.isA(String.class)
)
).andThrow(new UnknownCurrencyException());

EasyMock.replay(exchangeRateService);

converter.convert(10.0, "EUR", "-UNKNOWN-");
}

@Test(alwaysRun = true,
dependsOnMethods = "testConvertWithUnknownCurrency")
public void verifyAfterTestConvertWithUnknownCurrency() {
EasyMock.verify(exchangeRateService);
}

The test works as expected. Smile :-)

Updated: Re-think about my TestNG test version, I will remove alwaysRun = true from verifyAfterTestConvertWithUnknownCurrency(). Why? 'Cause if testConvertWithUnknownCurrency() fails, it means the test fail, don't need to waste my time to verify something it was failed.

One reason to use dependent methods 'cause it makes the test clearly. I know exactly where the test fails, 'cause it doesn't throw exception or 'cause EasyMock.verify() fails.

No comments: