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

如何使用Mockito模拟链式方法调用?含业务代码场景

Mockito模拟链式方法调用的分步指南(针对你的ViewModel创建函数)

嘿,我来帮你搞定这个Mockito模拟链式调用的问题!你的createViewModel函数里有一串很长的链式调用,要mock它其实不难,只需要逐层拆解每一步的对象,然后依次设置mock的返回值就行。下面是具体的步骤和代码示例:

第一步:识别所有需要Mock的对象

先把你的链式调用拆解开,看看每一步返回的是什么对象:
product.getProductData().offers().get(0).productCategory().asProductCategory().inlined().map(...).map(...).orElse("")
拆解后需要mock的对象包括:

  • ClassB(也就是传入的product参数)
  • ProductData(product.getProductData()的返回值)
  • Offer(offers列表的第一个元素)
  • productCategory()返回的包装类(假设叫WrappedProductCategory,你需要替换成实际类型)
  • ProductCategory(asProductCategory()的返回值,以及inlined()里的对象)
  • ProductCategory.GLProductGroup(glProductGroup()的返回值)

第二步:创建Mock对象

你可以用Mockito的@Mock注解或者Mockito.mock()方法来创建这些mock实例,比如在测试类里:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import java.util.Optional;

@ExtendWith(MockitoExtension.class)
class YourViewModelCreatorTest {

    // 声明所有需要mock的对象(替换成你实际的类名)
    @Mock
    private ClassB mockProduct;
    @Mock
    private ProductData mockProductData;
    @Mock
    private Offer mockOffer;
    @Mock
    private WrappedProductCategory mockWrappedProductCategory;
    @Mock
    private ProductCategory mockInlinedProductCategory;
    @Mock
    private ProductCategory.GLProductGroup mockGLProductGroup;

    // 测试方法写在这里
}

第三步:逐层设置Mock的返回值

从最内层的对象开始设置返回,这样外层的链式调用才能正确拿到预期值:

@Test
void createViewModel_ShouldSetName_FromGLProductGroup() throws ModuleException {
    // 1. 设置最内层:GLProductGroup的symbol返回预期字符串
    when(mockGLProductGroup.symbol()).thenReturn("ELECTRONICS");

    // 2. 设置inlined的ProductCategory返回这个GLProductGroup
    when(mockInlinedProductCategory.glProductGroup()).thenReturn(mockGLProductGroup);

    // 3. 设置asProductCategory()后的对象的inlined()返回包含mock对象的Optional
    when(mockWrappedProductCategory.asProductCategory().inlined()).thenReturn(Optional.of(mockInlinedProductCategory));
    // 注意:如果asProductCategory()直接返回ProductCategory类型,那改成:
    // when(mockInlinedProductCategory.inlined()).thenReturn(Optional.of(mockInlinedProductCategory));

    // 4. 设置Offer的productCategory()返回包装类对象
    when(mockOffer.productCategory()).thenReturn(mockWrappedProductCategory);

    // 5. 设置ProductData的offers()返回包含mockOffer的列表
    when(mockProductData.offers()).thenReturn(List.of(mockOffer));

    // 6. 设置ClassB的getProductData()返回mockProductData
    when(mockProduct.getProductData()).thenReturn(mockProductData);

    // 调用目标方法(替换成你的实际类名)
    YourViewModelCreator creator = new YourViewModelCreator();
    ClassA result = creator.createViewModel(mockProduct, null); // classCVar可以传null或者mock对象

    // 验证结果:name应该是我们设置的"ELECTRONICS"
    assertEquals("ELECTRONICS", result.getName());
}

额外提示:处理null分支

如果要测试product为null或者product.getProductData()为null的情况,只需要调整mock的返回值即可:

@Test
void createViewModel_ShouldSetEmptyName_WhenProductIsNull() throws ModuleException {
    YourViewModelCreator creator = new YourViewModelCreator();
    ClassA result = creator.createViewModel(null, null);

    assertEquals("", result.getName());
}

@Test
void createViewModel_ShouldSetEmptyName_WhenProductDataIsNull() throws ModuleException {
    when(mockProduct.getProductData()).thenReturn(null);

    YourViewModelCreator creator = new YourViewModelCreator();
    ClassA result = creator.createViewModel(mockProduct, null);

    assertEquals("", result.getName());
}

不推荐的方式:RETURNS_DEEP_STUBS

Mockito有个RETURNS_DEEP_STUBS选项可以一次性mock深层链式调用,但不建议用,因为它会让测试变得不透明,一旦链式调用有变化,测试很难排查问题。比如:

// 不推荐的写法,维护成本高
ClassB mockProduct = mock(ClassB.class, RETURNS_DEEP_STUBS);
when(mockProduct.getProductData().offers().get(0).productCategory().asProductCategory().inlined()
        .map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol).orElse(""))
        .thenReturn("ELECTRONICS");

这种写法看起来简洁,但出问题时很难定位,还是逐层mock更清晰可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:59:04