首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >thenAnswer时Mockito Varargs参数

thenAnswer时Mockito Varargs参数
EN

Stack Overflow用户
提问于 2022-10-12 10:20:02
回答 2查看 61关注 0票数 0

我不明白为什么在这里抛出类强制转换异常:

我有一个以字符串的变量作为参数的方法。

代码语言:javascript
复制
public List<A> getSomething(final String a, final String b, final Date c, final String d, final String e, final String... f) throws MyException {

   return valuesFromDB(a, b, c, d, e, f);

}

我已经模拟了方法的实现。

代码语言:javascript
复制
public List<A> getSomethingUnitTest(final String a, final String b, final Date c, final String d, final String e, final String... f) throws MyException {

   return valuesFromCSV(a, b, c, d, e, f);

}

用Mockito进行单元测试

代码语言:javascript
复制
@ExtendWith(MockitoExtension.class)
class AlgoTest {

    @Test
    void testExecute() throws MyException {
    
        when(myRealService.getSomething(anyString(), anyString(), any(Date.class), anyString(), anyString(), any()))
            .thenAnswer(i -> myMockedService.getSomethingUnitTest(i.getArgument(0), i.getArgument(1), i.getArgument(2), i.getArgument(3), i.getArgument(4), i.getArgument(5)));

        Output output = algo.execute();
        
        assertNotNull(output);
   
    }

}

当我运行测试时,会引发类强制转换异常

代码语言:javascript
复制
java.lang.ClassCastException: class java.lang.String cannot be cast to class [Ljava.lang.String; (java.lang.String and [Ljava.lang.String; are in module java.base of loader 'bootstrap')
at com.cmystuff.alghorithm.AlgoTest.lambda$2(AlgoTest.java:82)
at org.mockito.internal.stubbing.StubbedInvocationMatcher.answer(StubbedInvocationMatcher.java:40)
at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:99)
at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:33)
at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:82)
at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:56)
at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptSuperCallable(MockMethodInterceptor.java:141)

任何加注:

代码语言:javascript
复制
<String[]> String[] org.mockito.ArgumentMatchers.any()
Matches anything, including nulls and varargs. 

getArgument文档:

代码语言:javascript
复制
<String[]> String[] org.mockito.invocation.InvocationOnMock.getArgument(int index)

Returns casted argument at the given index. Can lookup in expanded arguments form getArguments().
This method is preferred over getArgument(int, Class) for readability. 
Please readthe documentation of getArgument(int, Class) for an overview of situations whenthat method is preferred over this one.

我也尝试使用anyString(),但是我得到了相同的类强制转换异常

代码语言:javascript
复制
@ExtendWith(MockitoExtension.class)
class AlgoTest {

    @Test
    void testExecute() throws MyException {
    
        when(myRealService.getSomething(anyString(), anyString(), any(Date.class), anyString(), anyString(), anyString()))
            .thenAnswer(i -> myMockedService.getSomethingUnitTest(i.getArgument(0), i.getArgument(1), i.getArgument(2), i.getArgument(3), i.getArgument(4), i.getArgument(5)));

        Output output = algo.execute();
        
        assertNotNull(output);
   
    }

}

这个问题似乎与一个值的varargs有关.如果我为varargs参数传递两个值

代码语言:javascript
复制
@ExtendWith(MockitoExtension.class)
class AlgoTest {

    @Test
    void testExecute() throws MyException {
    
        when(myRealService.getSomething(anyString(), anyString(), any(Date.class), anyString(), anyString(), anyString(), anyString()))
            .thenAnswer(i -> myMockedService.getSomethingUnitTest(i.getArgument(0), i.getArgument(1), i.getArgument(2), i.getArgument(3), i.getArgument(4), i.getArgument(5), i.getArgument(6)));

        Output output = algo.execute();
        
        assertNotNull(output);
   
    }

}

这个会很好的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-10-12 10:46:25

方法在运行时将varargs表示为以数组为其最后一个参数的方法。在源代码中可以将参数作为单独的值传递这一事实是语法上的一种选择。

代码的问题是i.getArgument(index)返回每个单独的值-它不会将varargs分组到数组中。

这与不正确的类型推断结合在一起--如果使用i.getArgument(5)调用i.getArgument(5),编译器不正确地假设它需要转换为String[],因此您的代码相当于:

代码语言:javascript
复制
when(myRealService.getSomething(
        anyString(),
        anyString(),
        any(Date.class),
        anyString(),
        anyString(),
        any())
).thenAnswer(i -> {
    String[] varargs = i.getArgument(5); // incorrect, Note that code works fine if you use String -> the compiler knows that you are using varargs syntax
    return myMockedService.getSomething(
            i.getArgument(0),
            i.getArgument(1),
            i.getArgument(2),
            i.getArgument(3),
            i.getArgument(4),
            varargs
            );
});

例如,您称之为:

代码语言:javascript
复制
myRealService.getSomething("0", "1", new Date(), "3", "4", "5", "6", "7");

  • i.getArgument(5)等于将此值转换为数组的“5”
  • (BOOM,ClassCastException)
  • you应该传递整个varagrs数组,而不是
  • )您可以轻松地将与原始varargs对应的值复制到(String[]类型)

的新数组中。

代码语言:javascript
复制
when(myRealService.getSomething(
        anyString(),
        anyString(),
        any(Date.class),
        anyString(),
        anyString(),
        any())
).thenAnswer(i -> {
    String[] varargFromInvocation = Arrays.copyOfRange(i.getArguments(), 5, i.getArguments().length, String[].class);
    return myMockedService.getSomething(
            i.getArgument(0),
            i.getArgument(1),
            i.getArgument(2),
            i.getArgument(3),
            i.getArgument(4),
            varargFromInvocation);
});

其他想法:如果您只想对这一种方法进行存根,也许可以:

service

  • override getSomething

  • pass将
  • 扩展到算法

更好的是:

SomethingRepository

  • use

  • 提取

  • DBSomethingRepository in prod

  • 使用CVSSomethingRepository测试
票数 2
EN

Stack Overflow用户

发布于 2022-10-14 09:32:33

关于Mockito的问题,还可以将最后一个any()参数更改为any(String[].class),以修复问题:

代码语言:javascript
复制
when(myRealService.getSomething(anyString(), anyString(), any(Date.class), anyString(), anyString(), any(String[].class)))
  .thenAnswer(i -> myMockedService.getSomethingUnitTest(i.getArgument(0), i.getArgument(1), i.getArgument(2), i.getArgument(3), i.getArgument(4), i.getArgument(5)));

不过,我同意Lesiak的观点,你应该重新考虑这些类的设计。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74040220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档