简体   繁体   English

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

[英]mockito.AdditionalAnswers.returnsFirstArg() for overloaded methods

I have a problem with returnsFirstArg for overloaded methods, where the firstArg is not nessessarily the same type as the return type. 对于重载的方法, returnsFirstArg存在问题,其中firstArg的类型不一定与返回类型相同。

  1. I want both methods to return the string value of the first argument. 我希望这两种方法都返回第一个参数的字符串值。
  2. Even better they always return the value of key 更好的是,他们总是返回key的值

Is there anyway to achieve this and get these Tests green? 无论如何,要实现这一目标并使这些测试达到绿色?

This is a minimum NOT working example, in real live Translator is more complex and can't be modified. 这是一个最低的NOT正常工作示例,在实际的Live Translator中更为复杂,无法修改。

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));
    }
}

I wouldn't bend over backwards to try to define some generic default behavior when creating the mock object. 创建模拟对象时,我不会弯腰尝试定义一些通用的默认行为。 You have two different methods, and could just specify two different behaviors explicitly: 您有两种不同的方法,可以只明确指定两种不同的行为:

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

EDIT: 编辑:
Addressing the added/clarified requirement in the comments could be problematic, unless you have a good way to recognize argument you want to return. 解决注释中添加/阐明的要求可能会遇到问题,除非您有一种很好的方法来识别要返回的参数。

Assuming you can use some straight-forward logic, like returning the first string argument, you could implement your own Answer : 假设您可以使用一些简单的逻辑,例如返回第一个字符串参数,则可以实现自己的Answer

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

translator = mock(Translator.class, returnsFirstString);

This can, of course, be refined with some different logic like applying to getText methods only, etc. 当然,这可以使用一些不同的逻辑来完善,例如仅应用于getText方法,等等。

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

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