mockito.AdditionalAnswers.returnsFirstArg()用于重载方法

时间:2017-12-07 09:10:10

标签: java junit mockito

我遇到returnsFirstArg重载方法的问题,其中firstArg与返回类型的类型不同。

  1. 我希望两种方法都返回第一个参数的字符串值。
  2. 更好的是,他们总是返回key
  3. 的值

    无论如何要实现这一目标并让这些测试成为绿色吗?

    这是一个最低限度的非工作示例,在实时翻译中更复杂,无法修改。

    package test;
    
    import static org.hamcrest.Matchers.is;
    import static org.mockito.Mockito.mock;
    import static org.hamcrest.MatcherAssert.assertThat;
    import static org.mockito.AdditionalAnswers.returnsFirstArg;
    
    import java.util.Locale;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.runners.MockitoJUnitRunner;
    
    @RunWith(MockitoJUnitRunner.class)
    public class TranslatorTest {
    
        private class Translator {
    
            String getText(final String key) {
                return "translated " + key;
            }
    
            String getText(final Locale locale, final String key) {
                return "translated " + key + " for locale " + locale;
            }
        }
    
        @Test
        public void test_withoutToString() throws Exception {
            final String key = "com.stackoverflow.translator.label";
            Translator translator = mock(Translator.class,  returnsFirstArg());
    
            assertThat(translator.getText(key), is(key));
    
            final Locale locale = new Locale("en_GB"); // java.lang.ClassCastException: java.util.Locale cannot be cast to java.lang.String
            assertThat(translator.getText(locale, key), is(key));
        }
    
        @Test
        public void test_withToString() throws Exception {
            final String key = "com.stackoverflow.translator.label";
            Translator translator = mock(Translator.class,  returnsFirstArg().toString());
    
            assertThat(translator.getText(key), is(key));
            /*
             * java.lang.AssertionError:
             *  Expected: is "com.stackoverflow.translator.label"
             *  but: was null
             */
    
            final Locale locale = new Locale("en_GB");
            assertThat(translator.getText(locale, key), is(key));
        }
    }
    

1 个答案:

答案 0 :(得分:2)

在创建模拟对象时,我不会向后弯曲以尝试定义一些通用的默认行为。您有两种不同的方法,可以明确指定两种不同的行为:

@Before
public void setUp() {
    translator = mock(Translator.class);
    when(translator.getText(any(), any()))
        .thenAnswer(AdditionalAnswers.returnsSecondArg());
    when(translator.getText(any()))
        .thenAnswer(AdditionalAnswers.returnsFirstArg());
}

修改:
解决评论中添加/澄清的要求可能会有问题,除非您有一个很好的方法来识别您想要返回的参数。

假设您可以使用一些直接逻辑,比如返回第一个字符串参数,您可以实现自己的Answer

Answer<Object> returnsFirstString =
        invocationOnMock -> Arrays.stream(invocationOnMock.getArguments())
                .filter(String.class::isInstance)
                .findFirst()
                .orElse(null);

translator = mock(Translator.class, returnsFirstString);

当然,这可以通过一些不同的逻辑进行改进,例如仅适用于getText方法等。