Spring Boot中JUnit5测试:如何Mock方法内新建的EventA实例
如何Mock方法内部新建的EventA实例
你当前的测试代码无效,核心原因是测试中创建的EventA spy对象,和consumeEvents方法内部new EventA()生成的实例完全是两个独立对象,mock的extractModel()不会对方法里的真实EventA生效。再加上你未mockevent.getPayload()的返回值,导致eventA.setPayload(null),执行extractModel()时触发空指针异常。
以下是两种可行的解决方案:
方案一:重构代码(推荐,符合可测试性设计)
把EventA的创建逻辑抽成Consumer类的可覆盖方法,测试时通过mock这个方法返回我们可控的EventA实例:
修改Consumer类:
public class Consumer { private final ConsumerInterface consumerInterface; public Consumer(ConsumerInterface consumerInterface) { this.consumerInterface = consumerInterface; } public void consumeEvents(Event event) { EventA eventA = createEventA(); eventA.setPayload(event.getPayload()); consumerInterface.handleEvent(eventA.extractModel()); } } // 抽离创建逻辑,供测试覆盖 protected EventA createEventA() { return new EventA(); } }
修改测试代码:
@ExtendWith(MockitoExtension.class) class ConsumerTest { @Mock ConsumerInterface consumerInterface; @Mock Event event; @Mock EventPayload eventPayload; @Spy private Consumer consumer; @BeforeEach public void setup(){ consumer = spy(new Consumer(consumerInterface)); } @Test public void consumeEvents() { // mock event.getPayload()避免空指针 when(event.getPayload()).thenReturn(new Payload()); // 替换为实际Payload类型或mock对象 // 让Consumer的createEventA方法返回我们的spy EventA EventA eventASpy = spy(new EventA()); doReturn(eventASpy).when(consumer).createEventA(); // mock extractModel返回预设的eventPayload doReturn(eventPayload).when(eventASpy).extractModel(); consumer.consumeEvents(event); verify(consumerInterface, times(1)).handleEvent(eventPayload); } }
方案二:使用Mockito-inline mock构造函数(无需修改原代码)
如果不想改动原业务代码,可以使用Mockito的mockConstruction功能(需依赖mockito-inline),直接拦截EventA的构造调用并返回mock对象:
测试代码:
@ExtendWith(MockitoExtension.class) class ConsumerTest { @Mock ConsumerInterface consumerInterface; @Mock Event event; @Mock EventPayload eventPayload; private Consumer consumer; @BeforeEach public void setup(){ consumer = new Consumer(consumerInterface); } @Test public void consumeEvents() { // mock event.getPayload()避免空指针 when(event.getPayload()).thenReturn(new Payload()); // 替换为实际Payload类型或mock对象 // 拦截EventA的构造过程,返回mock并配置方法行为 try (MockedConstruction<EventA> mockedEventA = mockConstruction(EventA.class, (mock, context) -> { when(mock.extractModel()).thenReturn(eventPayload); })) { consumer.consumeEvents(event); verify(consumerInterface, times(1)).handleEvent(eventPayload); } } }
注意事项:
- 使用该方案需要添加
mockito-inline依赖(Maven可在pom.xml中引入对应依赖); - 这种方式属于低侵入但测试耦合度较高的方案,优先推荐方案一的重构方式,让代码本身具备更好的可测试性。
内容的提问来源于stack exchange,提问作者Smaillns
相关产品推荐
相关产品推荐

