我试图用jUnit和Mockito测试我的实现,但是遇到了问题.这是一个非常简单的示例,解释了该问题
接口KeyValueInterface
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()返回之前设置的值.这当然不是模拟将要执行的操作,因为模拟除了您要执行的操作外不会执行任何其他操作.您要做的只是测试方法的约定,而无需假设接口的实现.所以你的测试应该是
@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);
}