You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在测试类中验证内部抛出的异常?

问题:如何断言被捕获的内部异常确实抛出?

我在测试类A,它会调用类B的methodB方法。B的methodB内部会抛出Exception,但该异常被catch块捕获后仅通过Logger打印日志。我需要断言这个内部异常确实被抛出,但当前测试代码报错。

相关代码

Class A

public class A {

    private static Logger logger;

    private B b;

    public A() {
        logger = LoggerFactory.getLogger("A");
        b = new B();
    }

    public void methodA() {
        b.methodB();
        logger.info("A");
    }
}

Class B

public class B {

    private static Logger logger;

    public B() {
        logger = LoggerFactory.getLogger("B");
    }

    public void methodB() {
        try {
            throw new Exception("NULL");
        } catch(Exception e) {
            logger.info("Exception thrown");
        }
    }
}

测试代码

@Test
public void testException() {
    A a = new A();
    a.methodA();
    assertThrows(Exception.class, () -> b.methodB());
}

遇到的错误

Expected java.lang.Exception to be thrown, but nothing was thrown.
org.opentest4j.AssertionFailedError: Expected java.lang.Exception to be thrown, but nothing was thrown.


解决方案

因为methodB内部已经捕获了异常,不会将异常抛出到方法外部,所以assertThrows无法直接检测到。你可以通过以下几种方式验证:

方法1:Mock Logger,验证日志输出

使用Mockito等工具mock B类的Logger,验证是否打印了对应的异常日志,间接证明异常被抛出并捕获。

示例测试代码:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class ATest {

    @Mock
    private Logger bLogger;

    @Test
    public void testExceptionThrownAndCaught() {
        // 替换B类的静态Logger为mock对象
        B.logger = bLogger;
        
        A a = new A();
        a.methodA();
        
        // 验证Logger是否打印了指定日志
        verify(bLogger).info("Exception thrown");
    }
}

方法2:使用PowerMock拦截异常抛出(不推荐修改代码时用)

如果无法修改原代码,可使用PowerMock拦截methodB内部的异常抛出动作,直接验证异常是否被抛出。

示例测试代码:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)
public class ATest {

    @Test(expected = Exception.class)
    public void testExceptionThrownInternally() throws Exception {
        // 部分mock B类,让methodB直接抛出异常
        B mockB = PowerMockito.spy(new B());
        PowerMockito.doThrow(new Exception("NULL")).when(mockB).methodB();
        
        // 替换A中的b实例为mock对象
        A a = new A();
        PowerMockito.field(A.class, "b").set(a, mockB);
        
        a.methodA();
    }
}

方法3:修改代码设计(推荐)

如果允许调整原代码,可以让methodB暴露捕获的异常,让测试更直接:

修改Class B:

public class B {

    private static Logger logger;
    private Exception caughtException;

    public B() {
        logger = LoggerFactory.getLogger("B");
    }

    public void methodB() {
        try {
            throw new Exception("NULL");
        } catch(Exception e) {
            caughtException = e;
            logger.info("Exception thrown");
        }
    }

    // 新增方法供测试获取捕获的异常
    public Exception getCaughtException() {
        return caughtException;
    }
}

测试代码:

import org.junit.Test;
import org.powermock.reflect.Whitebox;
import static org.junit.Assert.*;

public class ATest {

    @Test
    public void testExceptionThrown() {
        A a = new A();
        a.methodA();
        
        // 获取A中的b实例,验证捕获的异常
        B b = Whitebox.getInternalState(a, "b");
        assertNotNull(b.getCaughtException());
        assertEquals("NULL", b.getCaughtException().getMessage());
    }
}

内容的提问来源于stack exchange,提问作者adityaViswanatham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:15:30