使用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
相关产品推荐
相关产品推荐

