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

Java 8环境下验证匿名内部类方法抛出异常的Mockito测试问题

Java 8环境下验证匿名内部类方法抛出异常的Mockito测试问题

我看了你的代码和测试,发现测试失败的核心原因很明确:你只是触发了statusChange让代码走到创建MyIoClientBuilder并调用subscribeProcessed的步骤,但从来没有调用过MyInterface的myInnerMethod方法——JSON解析的逻辑根本没执行,自然不会抛出RuntimeException,这就是断言失败的原因。

要解决这个问题,我们需要分两步走:先重构代码让测试可控制,再调整测试逻辑验证异常。

第一步:重构MyIoClient,解除硬编码的依赖

你的MyIoClient里直接new MyIoClientBuilder(),这是硬编码依赖,导致测试时无法mock这个Builder,也就拿不到传入subscribeProcessed的MyInterface实例。我们可以通过依赖注入Supplier的方式,把Builder的创建逻辑暴露给测试:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.function.Supplier;

public class MyIoClient {
    private final Supplier<MyIoClientBuilder> builderSupplier;

    // 生产环境用的默认构造方法,保持原有逻辑
    public MyIoClient(ClientListener clientListener) {
        this(clientListener, MyIoClientBuilder::new);
    }

    // 测试专用构造方法,传入Builder的创建器
    MyIoClient(ClientListener clientListener, Supplier<MyIoClientBuilder> builderSupplier) {
        this.builderSupplier = builderSupplier;
        clientListener.addClientStatusListener(new StatusListener() {
            @Override
            public void statusChange(ClientStatus clientStatus) {
                if (clientStatus.equals(ClientStatus.AUTHORIZED)) {
                    builderSupplier.get()
                            .subscribeProcessed(new MyInterface() {
                                @Override
                                public void myInnerMethod(String jsonString) {
                                    try {
                                        Person person = new ObjectMapper().readValue(jsonString, Person.class);
                                        System.out.println("person = " + person);
                                    } catch (JsonProcessingException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                            }).build();
                }
            }
        });
    }
}

第二步:调整测试逻辑,捕获MyInterface实例并验证异常

现在我们可以mockMyIoClientBuilder,捕获传入subscribeProcessed的MyInterface实例,然后手动调用它的myInnerMethod传入无效JSON,验证是否抛出预期异常:

import org.junit.Test;
import org.mockito.ArgumentCaptor;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.*;

public class MyIoClientTest {

    @Test
    public void shouldThrowRuntimeExceptionWhenJsonInvalid() {
        // Arrange
        // 1. Mock ClientListener,触发statusChange到AUTHORIZED状态
        ClientListener clientListenerSpy = spy(ClientListener.class);
        doAnswer(invocation -> {
            StatusListener statusListener = invocation.getArgument(0);
            statusListener.statusChange(ClientStatus.AUTHORIZED);
            return null;
        }).when(clientListenerSpy).addClientStatusListener(any(StatusListener.class));

        // 2. Mock MyIoClientBuilder,捕获传入的MyInterface实例
        MyIoClientBuilder mockBuilder = mock(MyIoClientBuilder.class);
        ArgumentCaptor<MyInterface> myInterfaceCaptor = ArgumentCaptor.forClass(MyInterface.class);
        when(mockBuilder.subscribeProcessed(myInterfaceCaptor.capture())).thenReturn(mockBuilder);
        when(mockBuilder.build()).thenReturn(mockBuilder);

        // 3. 创建MyIoClient,传入mock的Builder Supplier
        new MyIoClient(clientListenerSpy, () -> mockBuilder);

        // 拿到捕获到的MyInterface实例
        MyInterface myInterface = myInterfaceCaptor.getValue();

        // Act & Assert:传入无效JSON,验证抛出异常
        String invalidJson = "{invalid: json}"; // 明显不符合JSON规范的字符串
        assertThatThrownBy(() -> myInterface.myInnerMethod(invalidJson))
                .isInstanceOf(RuntimeException.class)
                .hasCauseInstanceOf(JsonProcessingException.class); // 进一步验证异常根源
    }
}

关键逻辑说明

  1. 重构的意义:通过Supplier注入Builder的创建逻辑,让测试可以替换成mock的Builder,从而捕获到subscribeProcessed方法传入的MyInterface匿名实例。
  2. 捕获实例:用ArgumentCaptor捕获subscribeProcessed的参数,这样我们就能直接调用这个实例的myInnerMethod方法。
  3. 精准验证:不仅断言抛出RuntimeException,还验证它的根源是JsonProcessingException,这样测试的准确性更高。

这样调整后,测试就能准确验证当JSON无效时,代码会抛出预期的RuntimeException了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:23:02