Java 如何使用Mockito模拟方法调用链

Java 如何使用Mockito模拟方法调用链,java,junit,mockito,Java,Junit,Mockito,我有这样一个函数: @Override public ClassA createViewModel(ClassB product, ClassC classCVar) throws ModuleException { ClassA classAVar = ClassA.builder().build(); try { if (product !=

我有这样一个函数:

    @Override
        public ClassA createViewModel(ClassB product, ClassC classCVar)
                throws ModuleException
        {
            ClassA classAVar = ClassA.builder().build();
            try {
                if (product != null && product.getProductData() != null) {

                    String gl_name = product.getProductData().offers().get(0).productCategory().asProductCategory()
                            .inlined().map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol)
                            .orElse("");
                    classAVar.setName = gl_name;

                }
                return classAVar;
            } catch (Exception e) {
                // some lines of code.
            }
public String fetchGLNameFunction(ClassB product)
    {
        String gl_name_result = product.getProductData().offers().get(0).productCategory().asProductCategory()
                .inlined().map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol)
                .orElse("");
        return gl_name_result;
    }
@Mock
    private ClassA classAVar;
..........
............

@Test
    public void testfunction1() throws Exception
    {
        when(classAVar.fetchGLNameFromAmazonAPI(classBVar)).thenReturn("abc");
我这里有一行,比如字符串gl_name=。。。。。。。。。。。。 它包含一系列方法调用。 现在我想用Mockito模拟这个函数,并希望所有这些函数调用的最终结果,就像gl_name=“abc”

我该怎么做

我创建了一个新函数,并将方法调用链放入其中,如下所示:

    @Override
        public ClassA createViewModel(ClassB product, ClassC classCVar)
                throws ModuleException
        {
            ClassA classAVar = ClassA.builder().build();
            try {
                if (product != null && product.getProductData() != null) {

                    String gl_name = product.getProductData().offers().get(0).productCategory().asProductCategory()
                            .inlined().map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol)
                            .orElse("");
                    classAVar.setName = gl_name;

                }
                return classAVar;
            } catch (Exception e) {
                // some lines of code.
            }
public String fetchGLNameFunction(ClassB product)
    {
        String gl_name_result = product.getProductData().offers().get(0).productCategory().asProductCategory()
                .inlined().map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol)
                .orElse("");
        return gl_name_result;
    }
@Mock
    private ClassA classAVar;
..........
............

@Test
    public void testfunction1() throws Exception
    {
        when(classAVar.fetchGLNameFromAmazonAPI(classBVar)).thenReturn("abc");
现在我尝试创建一个类似这样的模拟:

    @Override
        public ClassA createViewModel(ClassB product, ClassC classCVar)
                throws ModuleException
        {
            ClassA classAVar = ClassA.builder().build();
            try {
                if (product != null && product.getProductData() != null) {

                    String gl_name = product.getProductData().offers().get(0).productCategory().asProductCategory()
                            .inlined().map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol)
                            .orElse("");
                    classAVar.setName = gl_name;

                }
                return classAVar;
            } catch (Exception e) {
                // some lines of code.
            }
public String fetchGLNameFunction(ClassB product)
    {
        String gl_name_result = product.getProductData().offers().get(0).productCategory().asProductCategory()
                .inlined().map(ProductCategory::glProductGroup).map(ProductCategory.GLProductGroup::symbol)
                .orElse("");
        return gl_name_result;
    }
@Mock
    private ClassA classAVar;
..........
............

@Test
    public void testfunction1() throws Exception
    {
        when(classAVar.fetchGLNameFromAmazonAPI(classBVar)).thenReturn("abc");

它仍然给我NullPointerException,因为它正在执行我新创建的函数。

Mockito
中,您需要定义模拟对象的行为

    //  create mock
    ClassB product = mock(ClassB.class);

    // Define the other mocks from your chain:
    // X, Y, Z, ...

    // define return value for method getProductData()
    when(product.getProductData()).thenReturn(X);
    when(X.offers()).thenReturn(Y);
    when(Y.get(0)()).thenReturn(Z); // And so on.... until the last mock object will return "abc"

您应该模拟要隔离的依赖项,而不是测试的数据/模型。
模拟测试方法的参数将使其可读性大大降低,因为您将不得不模拟许多事情


您的方法链有多个场景,因此通过创建一个对应于每个场景的B实例来测试每个场景。

您可以:1)创建一个ClassB对象,该链调用将导致“abc”。2) 或者你模拟一个classB对象,但是你必须模拟每个链接调用。这在某种程度上与得墨忒尔定律有关。3) 或者你在classB中创建了一个方法来执行所有的链式调用,这样你只需要模仿一个方法,我已经编辑了这个问题,并尝试实现了你说的第三个方法。但是它仍然给我带来了NullPointerException。你能发布你的整个测试吗?如何在测试中注入
classAVar
?您需要模拟
ClassA.builder().build()
并使其返回模拟对象
classAVar