java Mockito 允许不同的参数类型来模拟重载的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29365187/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 15:06:35  来源:igfitidea点击:

Mockito Allow different argument types to mock overloaded method

javaunit-testingjunitmockingmockito

提问by Chry007

For JUnit testing I want to mock an overloaded method. There is no need to implement several methods in the mockbuilder though. I want to do something like this:

对于 JUnit 测试,我想模拟一个重载的方法。但是不需要在模拟构建器中实现几个方法。我想做这样的事情:

Mockito.when(mock.getSomeInfo(Mockito.any(ArgumentType1.class) OR Mockito.any(ArgumentType2.class), Mockito.any(ArgumentType3.class))).then(new Answer<AnswerType>() {..}

I know it doesn't work with the ORstatement, but is there another way to do this in Mockito?

我知道它不适用于该OR语句,但是在 Mockito 中还有另一种方法吗?

回答by DTing

You can do this with a custom matcher.

您可以使用自定义匹配器执行此操作。

Warning: Be reasonable with using complicated argument matching, especially custom argument matchers, as it can make the test less readable. Sometimes it's better to implement equals() for arguments that are passed to mocks (Mockito naturally uses equals() for argument matching). This can make the test cleaner.

警告:合理使用复杂的参数匹配,尤其是自定义参数匹配器,因为它会降低测试的可读性。有时最好为传递给模拟的参数实现 equals() (Mockito 自然使用 equals() 进行参数匹配)。这可以使测试更干净。



public class TypeOrMatcher extends ArgumentMatcher<Object> {

  private final List<Class<?>> clazzes;

  public TypeOrMatcher(Class<?>...clazzes) {
    this.clazzes = new ArrayList<Class<?>>(clazzes);
  }

  public boolean matches(Object actual) {
    if (actual == null) {
      return false;
    }
    Class<?> actualClass = actual.getClass();
    for (Class<?> clazz : clazzes) {
      if (clazz.isAssignableFrom(actualClass) {
        return true;
      }
    }
    return false;
  }
}

TypeOrMatcher isTypeOneOrTwo = new TypeOrMatcher(
    ArgumentType1.class, ArgumentType2.class); 

Some mockObj = mock(Some.class);
when(mockObj.someMethod(argThat(isTypeOneOrTwo), any(ArgumentType3.class))
    .thenReturn(true);

回答by Tim van der Lippe

You can pre-create the answer object you want to return and then return this answer.

您可以预先创建要返回的答案对象,然后返回此答案。

class A {

    public int test(final String s) {
        return 0;
    }

    public int test(final int i) {
        return 0;
    }
}

And in the test method:

在测试方法中:

public void testAtest() {
    final A a = Mockito.mock(A.class);

    final Answer<Integer> answer = new Answer<Integer>() {

        @Override
        public Integer answer(final InvocationOnMock invocation) throws Throwable {
            return 0;
        }
    };

    Mockito.when(a.test(Matchers.anyInt())).then(answer);
    Mockito.when(a.test(Matchers.anyString())).then(answer);
}

回答by David Doan

For an example I have a service class that will be called from testing method:

例如,我有一个将从测试方法调用的服务类:

public interface AService{

   public ReturnObject addNewItem(String param1, String param2);

   public ReturnObject addNewItem(String param1, String param2, boolean isOk);
}

Have a method in MainServiceImpl class will call an overloaded method like below:

在 MainServiceImpl 类中有一个方法将调用一个重载方法,如下所示:

@Service("mainService")
public class MainServiceImpl implements MainService {

    @Autowired
    private AService aService;

    public ReturnObject saveItem(String itemName, String itemCode){
        return  aService.addNewItem(itemName, itemCode);
    }
}

So when we have to write unit test for saveItemthe method which already calls to overloaded method as addNewItem, if you had used normal way to create a mock then you answer will not return what you want in answer object return.

因此,当我们必须为saveItem已经调用重载方法 as 的方法编写单元测试时addNewItem,如果您使用正常方式创建模拟,那么您的 answer 将不会在 answer 对象 return 中返回您想要的内容。

@RunWith(PowerMockRunner.class)
@PrepareForTest({ })
public class ItemTest{

    @Test
    public void testSaveItem() throws Exception {
       //create a real object of MainServiceImpl 
       MainServiceImpl  mainService = new MainServiceImpl();
       //create a normal way for a mocking object
       AService aService = Mockito.mock(AService.class);
       // Add mock object to MainServiceImpl instance
       ReflectionTestUtils.setField(mainService, "aService", aService);

       //Mock when aService call to addNewItem() method
       PowerMockito.when(aService , "addNewItem", Mockito.anyString(), Mockito.anyString()).then(new Answer<ReturnObject>() {
            @Override
            public ReturnObject answer(InvocationOnMock invocation) throws Throwable {
                return new ReturnObject("saveOK");
            }
        });

        ReturnObject returnObj = mainService.saveItem("Book", "Code123");

        Assert.assertNotNull(returnObj);
    }
}

Try to replace testSaveItem above by with testSaveItem below then success:

尝试用下面的 testSaveItem 替换上面的 testSaveItem 然后成功:

@Test
public void testSaveItem() throws Exception {
    //create a real object of MainServiceImpl 
    MainServiceImpl  mainService = new MainServiceImpl();

    //create a special way for a mocking object by add 
    //the answer at create the mock object

    final Answer<ReturnObject> answer = new Answer<ReturnObject>() {
        @Override
        public ReturnObjectanswer(final InvocationOnMock invocation)    throws Throwable {
            return new ReturnObject("saveOK");
        }
    };
    AService aService = Mockito.mock(AService.class, answer);

    // Add mock object to MainServiceImpl instance
    ReflectionTestUtils.setField(mainService, "aService", aService);

    //Mock when aService call to addNewItem() method
    PowerMockito.when(aService , "addNewItem", Mockito.anyString(), Mockito.anyString()).then(new Answer<ReturnObject>() {
            @Override
            public ReturnObject answer(InvocationOnMock invocation) throws Throwable {
                return new ReturnObject("saveOK");
            }
        });

    ReturnObject returnObj = mainService.saveItem("Book", "Code123");

    Assert.assertNotNull(returnObj);
}

回答by Nayeem

As mentioned on the mockito github:

正如在 mockito github 上提到的:

It looks like this has to do with calling when the second time. I couldn't find what was going on, but the second when doesn't attempt to add the mock logic, it just calls the method. Replacing with doReturn().when() works.

看起来这与第二次调用有关。我找不到发生了什么,但是第二次没有尝试添加模拟逻辑,它只是调用方法。替换为 doReturn().when() 有效。

    doReturn(expected1).when(overloadedMethods).getString(any());
    doReturn(expected2).when(overloadedMethods).getString(any(), any());

https://github.com/mockito/mockito/issues/1496#issuecomment-423310950DavidTanner

https://github.com/mockito/mockito/issues/1496#issuecomment-423310950DavidTanner