I have set up some JUnit (4.12) test with the ExpectedException feature, and I would like the test to continue after the expected exception. But I never see the log '3', as the execution seems to stop after the exception, event if catch?
Is this actually possible, and how?
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testUserAlreadyExists() throws Exception {
log.info("1");
// Create some users
userService.createUser("toto1");
userService.createUser("toto2");
userService.createUser("toto3");
Assert.assertTrue( userService.userExists("toto1") );
Assert.assertTrue( userService.userExists("toto2") );
Assert.assertTrue( userService.userExists("toto3") );
log.info("2");
// Try to create an existing user
exception.expect(AlreadyExistsException.class);
userService.createUser("toto1");
log.info("3");
}
You cannot do that, when the exception is thrown it's thrown for real, ExpectedException
rule or not.
If you really want this kind of behaviour, you can go back to the "old school" pattern:
try {
userService.createUser("toto1");
Assert.fail("expecting some AlreadyExistsException here")
} catch (AlreadyExistsException e) {
// ignore
}
log.info("3");
But I wouldn't bother for some log.
This SO solution seems to do what you want to do: JUnit continue to assert things after expected exception
I myself was thinking something similar. To continue with the test, you would have to catch the exception yourself in the test. This solution shows an elegant way of doing that.
Note: If you make a rule to expect an exception (as you did), the test will return successful as soon as that exception is thrown.
Reference: http://junit.org/javadoc/latest/org/junit/rules/ExpectedException.html
First of all your test doesn't test one thing. It tests "userExists" and "createUser" under different conditions a.k.a. different scenarios. This is called an AssertionRoulette. You wouldn't need a hack to continue to log "3", if you would write tests, that fail fo the right reason.
If the tests fail for the right reason, you can see the scenario why it fails without doing all the logging stuff. The Junit-Runner does the logging for you already.
@Test
public void testUserExists_UserCreatedUserNotExistent_expectTrue()
{
// Create some users
userService.createUser("toto1");
// Assert That user exists
Assert.assertTrue( userService.userExists("toto1") );
}
@Test
public void testCreateUser_UserAlreadyCreated_expectAlreadyExistsExceptionIsThrown()
{
// Create some users
userService.createUser("toto1");
// Try to create an existing user
exception.expect(AlreadyExistsException.class);
userService.createUser("toto1");
}
If you don't want to add a lot of similar test methods for something that has many options to throw the expected exception and want to verify that it actually throws on all of the desired cases within a single unit-test instead, I'd suggest this (not pretty maybe) helpful schema:
@Test
public void testThatSomethingExpectedlyFails() {
for (int i = 1; i <= 3; i++) {
try {
switch (i) {
case 1: // smth here throws the exception when configuration #1;
case 2: // smth here throws the exception when configuration #2;
case 3: // smth here throws the exception when configuration #3;
}
} catch (ExceptionThatIsExpected expected) {
continue;
} catch (Exception unexpected) {
/* the test must fail when an unexpected exception is thrown */
fail("The test has failed due to an unexpected exception: " + unexpected.getMessage()); // or just re-throw this exception
}
/* the test must fail when a case completes without the expected exception */
fail("No expected exception occurred at case " + i);
}
}
The one could also iterate items (and even execute functions) of some preliminarily prepared list instead of switch-case with hard-coded integers.