Mockito – 存根抽象父类方法

我看到非常奇怪的行为试图存根一个在抽象父类MyAbstractBaseClass定义的类MyClass的方法myMethod(param)

当我尝试存根(使用doReturn("...").when(MyClassMock).myMethod(...)等)此方法失败时,在不同的场景下抛出不同的exception。 在该行上抛出exception。

当我使用doReturn("...").when(MyClassMock).myMethod(CONCRETE PARAM CLASS OBJECT) ,我得到以下exception:

 org.mockito.exceptions.misusing.WrongTypeOfReturnValue: String cannot be returned by hasValidExpirationDate() hasValidExpirationDate() should return boolean at ... 

hasValidExpirationDate()不是一个被存根的方法,但它是由抽象基类中MyMethod(param)的真实实现MyMethod(param)

当我使用doReturn("...").when(MyClassMock).myMethod(any(PARAMCLASS.class)) ,我得到以下exception:

 org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 0 matchers expected, 1 recorded. This exception may occur if matchers are combined with raw values: 

但是当我在子类MyClass定义方法myMethod(param) ,代码不再失败。 我在MyClass具体实现只是调用super.myMethod(param)并返回它,因此除了修复unit testing之外它没有任何影响。 所以看起来Mockito只能在类中定义的存根方法被模拟自己,而不是超类。

我正在阅读Mockito文档,我不知道它所说的inheritance方法无法被删除。

myMethod(param)既不是static也不是final

码:

BaseCard

 import java.io.Serializable; public class BaseCard implements Serializable { public boolean hasValidExpirationDate() { return true; } } 

Card

 abstract class Card extends BaseCard { public Card () { } public String getUnexpiredStringForNetwork(){ //If the date is invalid return empty string, except for Discover. if( ! hasValidExpirationDate()){ return "hi"; } return "hello"; } } 

DecryptedCard类:

 public class DecryptedCard extends Card { } 

MyTest类:

 import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import org.junit.Test; public class MyTest { @Test public void test() { DecryptedCard decryptedCardMock = mock(DecryptedCard.class); doReturn("ABC").when(decryptedCardMock).getUnexpiredStringForNetwork(); } } 

失败:

 org.mockito.exceptions.misusing.WrongTypeOfReturnValue: String cannot be returned by hasValidExpirationDate() hasValidExpirationDate() should return boolean *** If you're unsure why you're getting above error read on. Due to the nature of the syntax above problem might occur because: 1. This exception *might* occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency testing. 2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method. at Card.getUnexpiredStringForNetwork(Card.java:10) at DecryptedCard.getUnexpiredStringForNetwork(DecryptedCard.java:1) at MyTest.test(MyTest.java:13) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

根据这个SO答案 ,当父类是非公开的时,模拟行为不能得到保证,如问题212中所述 。

(感谢Brice在另一个post中给出了很好的答案,感谢Vladimir,JB Nizet和acdcjunior在评论主题中共享调试进度!)

哇! 就是这样!

我得到了奇怪的exception:

 org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced argument matcher detected here: -> at com.medziku.motoresponder.logic.ExposedResponder.createSettings(ResponderTest.java:163) -> at com.medziku.motoresponder.logic.ExposedResponder.createSettings(ResponderTest.java:163) You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains("foo")) 

虽然一切都是正确的。 我试图从mock类的超类中模拟方法,这个超类与mock类在同一个文件中,所以它不公开,并且出现了那些奇怪的错误。 在将超类移动到单独的文件并将其设置为公共之后,问题就消失了!