如果抛出 JUnit ExpectedException 后如何继续测试?

How to continue test after JUnit ExpectedException if thrown?

我已经使用 ExpectedException 功能设置了一些 JUnit (4.12) 测试,我希望测试在出现预期异常后继续。但是我从来没有看到日志“3”,因为执行似乎在异常之后停止了,event if catch?

这真的可能吗?如何实现?

@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");
}

你不能那样做,当抛出异常时,它是真实抛出的,ExpectedException规则与否。

如果你真的想要这种行为,你可以回到"old school"模式:

try {
    userService.createUser("toto1");
    Assert.fail("expecting some AlreadyExistsException here")
} catch (AlreadyExistsException e) {
    // ignore
}

log.info("3");

但我不会为一些日志而烦恼。

这个 SO 解决方案似乎可以满足您的需求:JUnit continue to assert things after expected exception

我自己也在想类似的事情。要继续测试,您必须自己在测试中捕获异常。此解决方案展示了一种优雅的方式。

注意:如果您制定了预期异常的规则(就像您所做的那样),则一旦抛出该异常,测试就会 return 成功。 参考:http://junit.org/javadoc/latest/org/junit/rules/ExpectedException.html

首先你的测试没有测试一件事。它在不同条件 a.k.a 下测试 "userExists" 和 "createUser"。不同的场景。这称为 AssertionRoulette。如果您要编写测试,那么您将不需要 hack 来继续记录“3”,因为正确的原因而失败。

如果测试由于正确的原因而失败,您可以在不执行所有日志记录的情况下查看失败的场景。 Junit-Runner 已经为您完成了日志记录。

@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");    
}

如果你不想为有很多选项的东西添加很多类似的测试方法来抛出预期的异常,并且想验证它是否真的抛出 all相反,在单个单元测试中的所需案例中,我建议这个(不太可能)有用的模式:

@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);
    }
}

还可以迭代一些预先准备好的列表的项目(甚至执行函数),而不是使用硬编码整数的 switch-case。