的Mockito。如何根据模拟对象返回一个布尔值作为参数?

时间:2017-09-06 20:21:13

标签: java spring-boot junit mockito

Class A
{
public B makeB(int q)
    {
        return new B(q);
    }
    public boolean evaluate(int q)
    {
        B b = makeB(q);
        boolean result = b.get();
        return result;
    }
}

Class B
{
    int e;
    public B(int w)
    {
        e=w;
    }
    public boolean get()
    {
        //return boolean based on object B
    } 
}

Class ATest
{
    A a = spy(A.class);
    B b1 = mock(B.class);
    B b2 = mock(B.class);

    doReturn(b1).when(a).makeB(5);
    doReturn(b2).when(a).makeB(10);

    when(b1.get()).thenReturn(true);
    when(b2.get()).thenReturn(false);

    a.evaluate();
}

=======================

这里我希望当对象B包含值5时从方法评估返回true,如果它包含值10则返回false。

B类来自外部图书馆。

单元测试和模拟新手。

3 个答案:

答案 0 :(得分:5)

其他答案在技术上是正确的,但第一个要理解:你应该努力使用这样的模拟框架。

请记住:模拟框架的目的只是 ,以使测试成为可能/更容易。你的嘲笑规范应该尽可能简单。含义:不是考虑让模拟在不同的参数上给出不同的结果 - 更好的解决方案是使用不同的测试和模拟规范,例如:

@Test 
public void testFooWithA() {
  when(someMock.foo(eq(whateverA)).thenReturn(bar);
  ...

@Test 
public void testFooWithB() {
  when(someMock.foo(eq(whateverB)).thenReturn(somethingElse);
  ...

在某些情况下,您可以编写更复杂的代码,以使您的模拟“更加智能”。但是大多数时候我必须这样做 - 我支持了,并且简化了我的测试设计。换句话说:当你的测试变得“太复杂”时 - 通常原因是测试中的太复杂的类/方法。

答案 1 :(得分:0)

您可以使用Mockito的Answer界面实现这一目标。它使您可以访问调用的实际参数,并且可以基于此区分返回的值。

给定界面

interface Measurer {
    int measureLength(String s);
}

示例用法可能看起来像

Measurer measurer = Mockito.mock(Measurer.class);
Mockito.when(measurer.measureLength(Mockito.any(String.class)))
        .then((Answer<Integer>) invocationOnMock -> {
            String arg = invocationOnMock.getArgumentAt(0, String.class);
            if (arg.length() < 10) {
                // mock Measurer can measure only short strings
                return arg.length();
            }
            else {
                return 42;
            }
        });

System.out.println(measurer.measureLength("abc")); // 3
System.out.println(measurer.measureLength("abcdefghijklmn")); // 42

答案 2 :(得分:0)

在这种情况下,你可以这样做:

doAnswer(new Answer<Boolean>() {
     public Boolean answer(InvocationOnMock invocation) {
         return invocation.getArgument(0) == 5;
     }}).when(a.evaluate());

如果你问如何获得&#39; b&#39;的实际价值?在A#evaluate()的实际实现中,你可以为两个模拟器添加一个makeB的答案,将一个局部变量设置为返回的B实例,这样你就知道它上次调用时返回的是什么,然后你可以根据该局部变量的值得到evaluate()返回的答案。

那是:

B lastB = null;
Answer<B> lastBAnswer = new Answer<B>() {
  public B answer(InvocationOnMock invocation) {
    if (invocation.<Integer>getArgument(0) == 5) {
      lastB = b1;
    } else {
      lastB = b2;
    }
    return lastB;
  }
};
doAnswer(lastBAnswer).when(a).makeB(any());
doAnswer(new Answer<Boolean>() {
  public Boolean answer(InvocationOnMock invocation) {
    return lastB.get();
  }
}).when(a).evaluate();

我不会推荐这条路径,因为它依赖于时间凝聚力,但是对于测试它可能是可以接受的。

注意:通过StackOverflow回答而不进行语法检查。可能稍微偏离,但这是一个粗略的想法。