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

PowerMock使用expectNew创建UserPersistor时生成真实对象而非Mock对象问题

业务代码

public  class PersistenceManager {

    public boolean addUser(User user) {
        UserPersistor userPersistor = new UserPersistor(user) {

            @Override
            void somemethod() {
                // TODO Auto-generated method stub
                
            }
            
        };
        userPersistor.addUser();
        System.out.println("PersistenceManager added user ");
        return true;
    }
    
    
    class User {
        
        public String firstName;
        public String lastName;
        
        
        public User(String firstName, String lastName) {
            super();
            this.firstName = firstName;
            this.lastName = lastName;
        }       
    }
    
    abstract class UserPersistor {
        
        public UserPersistor( ) {
            
        }
        public UserPersistor(User user) {
            
        }
        public void addUser() {
            System.err.println("UserPersistor added user ");
        }
        abstract void somemethod();
    }
}  

单元测试代码

import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.expectNew;
import static org.powermock.api.easymock.PowerMock.expectLastCall;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest( PersistenceManager.class )
public class PersistenceManagerTest {
    
    private User user = null;
    
    @Before
    public void before() throws Exception {
        
        user = createMock(User.class);      
        UserPersistor userPersistor = createMock(UserPersistor.class);
        userPersistor.addUser();
        expectLastCall();
        
        expectNew(UserPersistor.class, user).andReturn(userPersistor);      

        PowerMock.replayAll();
    }
    @Test
    public void testaddUser() {

        PersistenceManager tested = new PersistenceManager();
        tested.addUser(user);
        PowerMock.verifyAll();
    }
}
问题根因
  • 业务代码中实例化的是继承UserPersistor的匿名内部类,而非UserPersistor本身。expectNew(UserPersistor.class, user)只会拦截直接实例化UserPersistor类的操作,无法匹配匿名子类的实例化逻辑,导致拦截失效,真实对象被创建。
  • UserPersistor是PersistenceManager的非静态内部类,它的所有构造器都会隐式接收外部类PersistenceManager的实例作为第一个入参,你写expectNew时只传入了user一个参数,和实际构造器的参数列表不匹配,进一步导致拦截规则无法命中。
  • 匿名内部类不在@PrepareForTest的处理范围内,PowerMock无法修改其字节码完成实例替换。
修复建议
  1. 优先调整业务代码,移除addUser方法中的匿名内部类写法,提前将UserPersistor的子类实现抽取为独立的普通类,保证expectNew可以匹配到目标类。
  2. 如果要保留非静态内部类结构,expectNew需要补全隐式的外部类参数,同时调整测试代码中PersistenceManager实例的创建时机,示例调整如下:
@Before
public void before() throws Exception {
    PersistenceManager tested = new PersistenceManager();
    user = createMock(User.class);      
    UserPersistor userPersistor = createMock(UserPersistor.class);
    userPersistor.addUser();
    expectLastCall();
    // 补全外部类实例作为第一个构造参数
    expectNew(UserPersistor.class, tested, user).andReturn(userPersistor);      
    PowerMock.replayAll();
}
  1. 不建议保留匿名内部类的写法,该写法会导致测试逻辑复杂度大幅提升,可维护性差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:06:01