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

Mockito+JUnit单元测试时引用传递的offers对象未更新问题

问题原因
  • 你用@Mock注解声明的OfferService对象默认所有方法都是桩实现,不会执行真实方法逻辑。即便添加doCallRealMethod配置,mock出来的OfferService实例内部的MyDAO依赖并没有被注入,执行真实方法也无法完成数据库查询和offers对象更新。
  • 测试类的setUp方法中ItemService是局部变量,testBuildItems方法无法访问该实例,会编译报错。
  • 原业务代码ItemService的构造函数仅接收OfferService一个入参,测试代码中传两个参数的写法不符合原有定义。
解决方案

方案1(推荐,符合单元测试隔离原则)

直接mock OfferService.fetchInfoFromDB方法的行为,手动更新传入的offers对象,不需要执行OfferService的真实逻辑:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ItemService.class)
public class ItemServiceTest{

    @Mock 
    private OfferService offerService;

    // 提升为成员变量,测试方法可访问
    private ItemService itemService;

    @Before
    public void setUp() throws Exception {
        // 匹配原有构造函数定义
        itemService = new ItemService(offerService);
    }

    @Test
    public void testBuildItems(){
        ItemInfo itemInfo = buildItemInfo();
        OfferDetail offerDetail = buildOfferDetail();

        // 用Answer拦截方法调用,手动更新传入的offers对象
        doAnswer(invocation -> {
            Offers<Offer> offers = invocation.getArgument(0);
            // 按照业务逻辑填充offers的内容,模拟真实方法的更新效果
            Offer mockOffer = new Offer();
            mockOffer.setDetail(offerDetail);
            offers.add(mockOffer);
            return null; // 原方法为void返回
        }).when(offerService).fetchInfoFromDB(any(Offers.class));

        List<Item> items = itemService.buildItems(itemInfo);
        Assert.assertNotNull(items);
        // 可补充断言验证items的属性是否符合预期
    }
}

方案2(需要执行OfferService真实逻辑时使用)

用@Spy代替@Mock声明OfferService,同时为其注入mock的MyDAO依赖:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ItemService.class)
public class ItemServiceTest{

    @Mock 
    private MyDAO myDao;
    // Spy默认执行真实方法,初始化时传入mock的myDao
    @Spy
    private OfferService offerService = new OfferService(myDao);

    private ItemService itemService;

    @Before
    public void setUp() throws Exception {
        itemService = new ItemService(offerService);
        // 如果OfferService没有接收MyDAO的构造函数,用反射赋值
        Field daoField = OfferService.class.getDeclaredField("myDao");
        daoField.setAccessible(true);
        daoField.set(offerService, myDao);
    }

    @Test
    public void testBuildItems(){
        ItemInfo itemInfo = buildItemInfo();
        OfferDetail offerDetail = buildOfferDetail();
        when(myDao.getDetailsById(Mockito.anyLong())).thenReturn(offerDetail);

        List<Item> items = itemService.buildItems(itemInfo);
        Assert.assertNotNull(items);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 15:24:08