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

x3naxklr  于 2022-11-08  发布在  其他
关注(0)|答案(3)|浏览(278)

我有一个这样的函数:

@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.
            }

这里有一行代码,比如String gl_name =............,其中包含了一系列的方法调用。现在我想用Mockito模拟这个函数,并希望得到所有这些函数调用的最终结果,比如gl_name =“abc”;
我该怎么做?
我创建了一个新函数,并将方法调用链放入其中,如下所示:

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,因为它正在执行我新创建的函数。

ntjbwcob

ntjbwcob1#

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"
eqqqjvef

eqqqjvef2#

您应该模拟您想要隔离的依赖项,而不是测试的数据/模型。
模拟被测试方法的参数会使它的可读性大大降低,因为您将不得不模拟许多东西。
您的方法链有多个场景,因此通过创建与每个场景相对应的B示例作为fixture来测试每个场景。

y53ybaqx

y53ybaqx3#

Mockito有一个名为 deep stubbing/mocking 的特性,它允许您将一个调用链模拟为一个单独的模拟。

Builder builder = Mockito.mock(Builder.class, Mockito.RETURNS_DEEP_STUBS);

Mockito.when(
    builder.newObject()
           .withId(1)
           .withName("My Object")
           .withDescription("Some description")
           .build()
).thenReturn(anObject);

// Use the mock...
someService.someServiceMethod(builder);

但是,应该注意的是,深度嘲笑通常是不鼓励的。在mockito代码的深处,你会发现一条注解,内容如下:* 每次一个嘲笑者返回嘲笑者,一个仙女就死了 *
有关何时使用深度嘲讽以及为什么使用深度嘲讽不好的提示,请参阅本页:https://tuhrig.de/everytime-a-mock-returns-a-mock-a-fairy-dies/
我特别建议不要单独地模拟每个对象/方法调用,因为即使是最小的重构也可能破坏测试代码。

相关问题