与Mockito接口的Mockinggetter/setter方法



我正试图用jUnit和Mockito测试我的实现,但遇到了问题。下面是一个非常简单的例子,它解释了的问题

接口KeyValue接口

public interface KeyValueInterface {
    public abstract String getKey();
    public abstract void setKey(String key);
    public abstract String getValue();
    public abstract void setValue(String value);
}

类KeyValueImpl

public class KeyValueImpl implements KeyValueInterface {
    private String key;
    private String value;
    @Override
    public String getKey() {
        return key;
    }
    @Override
    public void setKey(String key) {
        this.key = key;
    }
    @Override
    public String getValue() {
        return value;
    }
    @Override
    public void setValue(String value) {
        this.value = value;
    }
}

使用"业务逻辑"分类

public class ValueFinder {
    public KeyValueInterface findValueForKey(KeyValueInterface keyValue){
        keyValue.setValue("foo");
        return keyValue;
    }
}

jUnit测试类

import static org.junit.Assert.*;
import org.junit.Test;
import org.mockito.Mockito;
public class ValueFinderTest {
    @Test
    public void testNotMocked() {
        KeyValueInterface keyValue = new KeyValueImpl();
        keyValue = (new ValueFinder()).findValueForKey(keyValue);
        assertEquals("foo", keyValue.getValue()); // works fine
    }
    @Test
    public void testMocked1() {
        KeyValueInterface keyValue = Mockito.mock(KeyValueInterface.class);
        keyValue = (new ValueFinder()).findValueForKey(keyValue);
        assertEquals("foo", keyValue.getValue()); // java.lang.AssertionError:
                                                    // expected:<foo> but
                                                    // was:<null>
    }
    @Test
    public void testMocked2() {
        KeyValueInterface keyValue = Mockito.mock(KeyValueInterface.class);
        keyValue = (new ValueFinder()).findValueForKey(keyValue);
        Mockito.when(keyValue.getValue()).thenCallRealMethod();
        Mockito.doCallRealMethod().when(keyValue).setValue(Mockito.any(String.class));
        assertEquals("foo", keyValue.getValue()); // org.mockito.exceptions.base.MockitoException:
                                                    // Cannot call real method
                                                    // on java interface.
                                                    // Interface does not have
                                                    // any implementation!
                                                    // Calling real methods is
                                                    // only possible when
                                                    // mocking concrete classes.
    }
}

我的问题是,由于我无法控制的技术原因,我需要模拟KeyValue。因此,我不能只使用testNotMocked()方法。此外,由于我无法控制的技术原因,我不得不模拟接口(而不是类)。

有什么办法做到这一点吗?

非常感谢。

如果您要编写正在测试的方法的javadoc,甚至不知道接口的任何方法在做什么,那么您将编写以下内容:

/**
 * Sets "foo" as the value of the given keyValue, and returns it
 */

您甚至不应该假设getValue()返回之前设置的值。这肯定不是mock要做的,因为mock除了你告诉它做的事情之外什么都不做。你所要做的就是测试你的方法的契约,而不假设接口的实现。所以你的测试应该是

@Test
public void testMocked1() {
    KeyValueInterface keyValue = Mockito.mock(KeyValueInterface.class);
    KeyValueInterface result = (new ValueFinder()).findValueForKey(keyValue);
    // tests that the value has been set to "foo"
    verify(keyValue).setValue("foo");
    // tests that the method returns its argument
    assertSame(keyValue, result);
}

Mock对Impl类一无所知。所以,只需对setValue执行verify,或者使用spy来调用real方法。

如果您检查Mockito API中下面的mock方法,您可以看到它创建了给定类或接口的mock对象。

public static <T> T mock(java.lang.Class<T> classToMock)

因此,第一个方法testMocked1()的错误是有效的。实际上,您在那里所做的是间接地嘲笑该接口的impl。因此,当你这样做的时候,所有的方法都会被嘲笑,因为getValue()返回了一个String,所以String的默认值是null,所以会返回一个null。使用下面这样的ReflectionUtils直接设置键值

ReflectionTestUtils.setField(classObject, key,keyvalue); 

并在您的方法testMocked1()中执行以下操作

assertEquals("foo", keyValue.getValue());

类似地,对于第二个方法testMocked2(),也可以使用reflectionutils设置值,并使用Mockito 中的任何api方法

使用when/then配置mock。看见http://www.baeldung.com/mockito-behavior

相关内容

  • 没有找到相关文章

最新更新