JUnit 测试 ߞ分析预期异常

发布于 2024-10-08 10:44:31 字数 141 浏览 1 评论 0原文

在 JUnit 中,我目前正在使用注释来预期测试中出现异常。

有没有办法分析这个异常?例如,我期望出现 CriticalServerException,但我还想验证 getMessage 方法的内容。

In JUnit, I'm currently using annotation to expect an exception in my tests.

Is there a way to analyse this exception? For example, I expect a CriticalServerException, but I also want to verify the content of the getMessage method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

深海蓝天 2024-10-15 10:44:31

如果您有 JUnit 4.7 或更高版本,请尝试 ExpectedException

这个问题中有一个例子,复制如下:

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

@Test
public void testRodneCisloRok(){
    exception.expect(IllegalArgumentException.class);
    exception.expectMessage("error1");
    new RodneCislo("891415",dopocitej("891415"));
}

If you have JUnit 4.7 or above try ExpectedException

There is an example in this question, which is copied below:

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

@Test
public void testRodneCisloRok(){
    exception.expect(IllegalArgumentException.class);
    exception.expectMessage("error1");
    new RodneCislo("891415",dopocitej("891415"));
}
小镇女孩 2024-10-15 10:44:31

我不确定你是否应该这样做。使用 try-catch 块来检查错误消息是如此junit3ish。现在我们有了这个很酷的功能,您可以编写 @Test(expected=CriticalServerException.class) 并且您想“返回”并再次使用 try-catch 来获取您期望的异常,只是为了检查错误信息?

IMO 您应该保留 @Test(expected=CriticalServerException.class) 注释并忽略错误消息。检查错误消息也可能很棘手,因为它是一个更“人类可读”的字符串而不是技术价值,因此可以进行很大的更改。您正在强制异常具有特定的错误消息,但您可能不知道谁生成了异常以及他选择了什么错误消息。

一般来说,您想要测试该方法是否引发异常,而不是实际的错误消息是什么样的。如果错误消息确实如此重要,您也许应该考虑使用它抛出的异常的子类,并在 @Test(expected=...) 中检查它。

I'm not sure if you should. Using a try-catch block to check the error message is so junit3ish. We have this cool feature now that you can write @Test(expected=CriticalServerException.class) and you want to go "back" and use try-catch again to fetch an exception you expect, just for checking the error message?

IMO you should stay for the @Test(expected=CriticalServerException.class) annotation and ignore the error message. Checking the error message, which can be changed a lot as it is a more "human readable" string and not a technical value, can also be tricky. You are forcing the exception to have a specific error message, but you might not know who generated the exception and what error message he chose.

In general you want to test if the method throws the exception or not, and not what the actual error message looks like. If the error message is really so important you should maybe consider using a subclass of the exception it throws and check it in @Test(expected=...).

左岸枫 2024-10-15 10:44:31
try{ 
    //your code expecting to throw an exception
    fail("Failed to assert :No exception thrown");
} catch(CriticalServerException ex){
    assertNotNull("Failed to assert", ex.getMessage()) 
    assertEquals("Failed to assert", "Expected Message", ex.getMessage());
}
try{ 
    //your code expecting to throw an exception
    fail("Failed to assert :No exception thrown");
} catch(CriticalServerException ex){
    assertNotNull("Failed to assert", ex.getMessage()) 
    assertEquals("Failed to assert", "Expected Message", ex.getMessage());
}
趴在窗边数星星i 2024-10-15 10:44:31
try
{
    // your code

    fail("Didn't throw expected exception");
}
catch(CriticalServerException e)
{
    assertEquals("Expected message", e.getMessage());
}
try
{
    // your code

    fail("Didn't throw expected exception");
}
catch(CriticalServerException e)
{
    assertEquals("Expected message", e.getMessage());
}
眼藏柔 2024-10-15 10:44:31
try {
    // test code invacation
    fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
    assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
try {
    // test code invacation
    fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
    assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
涫野音 2024-10-15 10:44:31

使用 MethodRule 作为通用解决方案,如果您有很多测试用例要测试

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 (CriticalServerException e) {
                    //Analyze the exception here
                }
            }
        };    
    }
}

,那么将 Rule 用于您的测试类:

@Rule public ExceptionRule rule = new ExceptionRule(); 

Use MethodRule as a common solution, if you have many test cases to test

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 (CriticalServerException e) {
                    //Analyze the exception here
                }
            }
        };    
    }
}

Then use the Rule to your test class:

@Rule public ExceptionRule rule = new ExceptionRule(); 
笑,眼淚并存 2024-10-15 10:44:31

我认为没有办法使用注释来做到这一点。您可能必须退回到 try-catch 方式,在 catch 块中您可以验证消息

I don't think there is a way of doing it using annotation. You may have to fall back to try-catch way where in the catch block you can verify the message

挽心 2024-10-15 10:44:31

使用catch-Exception

catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());

Use catch-exception:

catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
执笏见 2024-10-15 10:44:31

看看 Fluent-Exception-rule,它“结合了Junit ExpectedException规则和AssertJ的断言便利性。 ”

import pl.wkr.fluentrule.api.FluentExpectedException;
...
@Rule
public FluentExpectedException thrown = FluentExpectedException.none();

@Test
public void testDoSomethingCritical() {
    thrown.expect(CriticalServerException.class).hasMessage("Expected Message").hasNoCause();
    obj.doSomethingCritical();
}

Look at fluent-exception-rule, it "combines Junit ExpectedException rule and AssertJ's assertions convenience. "

import pl.wkr.fluentrule.api.FluentExpectedException;
...
@Rule
public FluentExpectedException thrown = FluentExpectedException.none();

@Test
public void testDoSomethingCritical() {
    thrown.expect(CriticalServerException.class).hasMessage("Expected Message").hasNoCause();
    obj.doSomethingCritical();
}
泅渡 2024-10-15 10:44:31

如果您想将消息与异常类型进行比较,那么您可以尝试下面的代码片段。

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

    expectedException.expect(IllegalArgumentException.class);
    expectedException.expectMessage("Parameter is not valid"); //check string contains
    expectedException.expectMessage(CoreMatchers.equalTo("Parameter is not valid")); //check string equals

注意:这适用于 junit 4.9 及以上版本。

If you want to compare message along with exception type then you can try below code snippet.

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

    expectedException.expect(IllegalArgumentException.class);
    expectedException.expectMessage("Parameter is not valid"); //check string contains
    expectedException.expectMessage(CoreMatchers.equalTo("Parameter is not valid")); //check string equals

Note: This will work for junit 4.9 onward.

吃颗糖壮壮胆 2024-10-15 10:44:31

Java 8 解决方案

这是我编写的一个实用函数:(

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

取自我的博客

按如下方式使用它:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}

此外,如果您想了解为什么您应该检查异常消息的一些原因,请参阅此:https://softwareengineering.stackexchange.com/a/278958/41811

Java 8 solution

Here is a utility function that I wrote:

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

(taken from my blog)

Use it as follows:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}

Also, if you would like to read some reasons why you should not want to check the message of your exception, see this: https://softwareengineering.stackexchange.com/a/278958/41811

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文