简体   繁体   English

Mockito - 使用 Varargs 参数模拟重载方法

[英]Mockito - Mocking overloaded methods with Varargs parameters

Mockito is hard to use when we need to mock overloaded methods when one of them is using varargs.当我们需要在其中一个使用可变参数时模拟重载方法时,Mockito 很难使用。 Consider the below methods from Spring's RestTemplate考虑 Spring 的RestTemplate的以下方法

void put(String url, Object request, Object... uriVariables) throws RestClientException;

void put(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;

Mocking the second one is straight forward, but mocking the first one is not possible as using any() would result in an ambiguous method call matching both the methods and there is no alternative to match just Object...模拟第二个是直接的,但模拟第一个是不可能的,因为使用any()会导致一个不明确的方法调用匹配这两个方法,并且没有其他方法可以只匹配Object...

Sharing the solution as Q & A that I arrived after putting some effort so as to help those in the same boat.将解决方案作为问答分享,这是我在努力之后到达的,以帮助那些在同一条船上的人。 All other alternatives welcome.欢迎所有其他选择。

Solution to this can be attempted by making use of the feature to provide a defaultAnswer to the mock.可以通过使用该功能为模拟提供defaultAnswer来尝试解决此问题。 The defaultAnswer will evaluate that the invocation is for the specific method and perform the needed action, and let the invocation follow the natural flow if the required method is not targeted. defaultAnswer 将评估调用是否针对特定方法并执行所需的操作,如果所需的方法不是目标,则让调用遵循自然流程。

This can be explained well with an example.这可以用一个例子很好地解释。 Consider the two overloaded methods in the class below:考虑下面类中的两个重载方法:

public class StringConcat {
    public String concatenate(int i, String... strings) {
        return i + Arrays.stream(strings).collect(Collectors.joining(","));
    }

    public String concatenate(int i, List<String> strings) {
        return i + strings.stream().collect(Collectors.joining(","));
    }
}

The second method can be mocked using Mockito like below:可以使用 Mockito 模拟第二种方法,如下所示:

StringConcat stringConcat = mock(StringConcat.class);
when(stringConcat.concatenate(anyInt(), anyList())).thenReturn("hardcoded value");

To represent varargs, we do not have anyVararg() method (deprecated and does not work, not sure if it worked in older versions).为了表示可变参数,我们没有anyVararg()方法(已弃用且不起作用,不确定它是否适用于旧版本)。 But the same can be handled by creating the mock with defaultAnswer like below:但是同样可以通过使用 defaultAnswer 创建模拟来处理,如下所示:

@Test
void testWithDefaultAnswer(){
    // Creating mock object with default answer
    StringConcat stringConcat = mock(StringConcat.class, invocation -> {
        Method method = invocation.getMethod();
        if (method.getName().contains("concatenate") && 
               method.getParameters()[method.getParameters().length-1].isVarArgs()){
            if(invocation.getArguments().length>=method.getParameterCount()){
                List varArgParams = Arrays.stream(invocation.getArguments())
                          .skip(method.getParameterCount()-1)
                          .collect(Collectors.toList());
                return invocation.getArguments()[0]+":"
                      +varArgParams.toString(); // mocked result when varargs provided
            }
            return ""+invocation.getArguments()[0]; // mocked result when varargs not provided
        }
        return Answers.RETURNS_DEFAULTS.answer(invocation); // Ensures seamless mocking of any other methods
    });

    // Mock any non varargs methods as needed
    when(stringConcat.concatenate(anyInt(), anyList())).thenReturn("hardcoded"); // mocking as usual

    // Test the mocks
    System.out.println(stringConcat.concatenate(1, "a", "b")); // default answer based mock, with varargs provided
    System.out.println(stringConcat.concatenate(1)); // default answer based mock, without varargs provided
    System.out.println(stringConcat.concatenate(1, Lists.newArrayList("a", "b"))); // mocked non varargs method
}

Output:输出:

1:[a, b]
1
hardcoded

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM