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

使用Mockito时创建Repository对象出现NullPointerException问题

排查Mockito测试DriveInteractor时的NullPointerException问题

我在使用Mockito编写DriveInteractor的测试类时遇到了NullPointerException,问题出在获取DriveRepository对象的环节。先贴出我的DriveInteractor代码:

public class DriveInteractor implements DriveContract.Interactor { 
    private final DriveRepository driveRepository; 

    public DriveInteractor(Context context) { 
        DriveApplication application = (DriveApplication) context.getApplicationContext(); 
        this.driveRepository = application.getDriveRepository(); 
    } 

    @Override 
    public List<Drive> getDrive() { 
        List<Drive> drives = driveRepository.getDrives(); 
        return drives; 
    } 
}

我的测试类开头是@RunWith...,但运行时调用getDrive()就会抛出NPE,因为driveRepository是null。

问题原因分析

你的DriveInteractor构造函数依赖Context去获取自定义的DriveApplication实例,再从中拿到driveRepository。但在测试环境中:

  • 没有真实的DriveApplication实例(或者实例中没有初始化driveRepository)
  • 你没有对Context、DriveApplication这些依赖进行mock,导致调用application.getDriveRepository()时返回null,最终调用driveRepository.getDrives()触发NPE。

解决方案

方案1:重构构造函数,使用依赖注入(推荐)

这是最优雅的解决方式,直接把DriveRepository作为构造参数传入,彻底解耦DriveInteractor与Context、Application的依赖,让测试变得简单:

修改后的DriveInteractor代码:

public class DriveInteractor implements DriveContract.Interactor { 
    private final DriveRepository driveRepository; 

    // 直接注入DriveRepository,无需依赖Context
    public DriveInteractor(DriveRepository driveRepository) { 
        this.driveRepository = driveRepository; 
    } 

    @Override 
    public List<Drive> getDrive() { 
        return driveRepository.getDrives(); 
    } 
}

对应的测试类可以直接mockDriveRepository,无需处理Context相关逻辑:

@RunWith(MockitoJUnitRunner.class)
public class DriveInteractorTest {

    @Mock
    private DriveRepository mockDriveRepository;

    private DriveInteractor driveInteractor;

    @Before
    public void setUp() {
        driveInteractor = new DriveInteractor(mockDriveRepository);
    }

    @Test
    public void testGetDrive_ReturnsExpectedDrives() {
        // 准备模拟数据
        List<Drive> mockDrives = Arrays.asList(new Drive(), new Drive());
        when(mockDriveRepository.getDrives()).thenReturn(mockDrives);

        // 调用测试方法
        List<Drive> result = driveInteractor.getDrive();

        // 验证结果
        assertEquals(mockDrives, result);
        verify(mockDriveRepository, times(1)).getDrives();
    }
}

方案2:Mock所有依赖对象(适合无法修改原有代码的场景)

如果暂时不能修改DriveInteractor的构造函数,那需要把Context、DriveApplication都mock出来,并设置正确的返回逻辑,确保driveRepository不为null:

@RunWith(MockitoJUnitRunner.class)
public class DriveInteractorTest {

    @Mock
    private Context mockContext;

    @Mock
    private DriveApplication mockDriveApplication;

    @Mock
    private DriveRepository mockDriveRepository;

    private DriveInteractor driveInteractor;

    @Before
    public void setUp() {
        // 让Context返回mock的DriveApplication
        when(mockContext.getApplicationContext()).thenReturn(mockDriveApplication);
        // 让mock的Application返回mock的Repository
        when(mockDriveApplication.getDriveRepository()).thenReturn(mockDriveRepository);
        
        // 初始化Interactor
        driveInteractor = new DriveInteractor(mockContext);
    }

    @Test
    public void testGetDrive() {
        List<Drive> mockDrives = Arrays.asList(new Drive());
        when(mockDriveRepository.getDrives()).thenReturn(mockDrives);

        List<Drive> result = driveInteractor.getDrive();

        assertEquals(1, result.size());
        verify(mockDriveRepository).getDrives();
    }
}

总结

方案1的依赖注入方式更推荐,它让代码的耦合度更低,测试逻辑更清晰,也符合面向对象的设计原则。方案2是妥协的解决方式,适合不能修改原有代码的场景,但需要维护更多的mock逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:36:29