我正在尝试匹配我在Dao类中使用的这个方法。但我总是得到以下异常,表明没有对该方法进行调用。
要么是方法不匹配,要么是我做错了什么。
String pSql = "SELECT * FROM employee";
Object[] pArgs = new Object[] {""};
int[] pArgTypes = new int[] {};
/* Return 1 when the call to update() is made indicating a successful database update */
when(mJdbcTemplate.update(anyString(), aryEq(pArgs), aryEq(pArgTypes))).thenReturn(1);
以下是异常的堆栈跟踪:
Wanted but not invoked:
jdbcTemplate.update(<any>, <any>, <any>);
-> at com.test.GenericDaoJdbcImplTest$WhenInsertUpdateDeleteIsCalledWith.successfulUpdateShouldReturnTrue(GenericDaoJdbcImplTest.java:197)
However, there were other interactions with this mock:
-> at com.test.GenericDaoJdbcImplTest.insertUpdateDelete(GenericDaoJdbcImpl.java:121)
at org.mockito.exceptions.Reporter.wantedButNotInvoked(Reporter.java:269)
at org.mockito.internal.verification.checkers.MissingInvocationChecker.check(MissingInvocationChecker.java:42)
at org.mockito.internal.verification.Times.verify(Times.java:36)
at org.mockito.internal.verification.MockAwareVerificationMode.verify(MockAwareVerificationMode.java:21)
at org.mockito.internal.MockHandler.handle(MockHandler.java:80)
at org.mockito.internal.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:36)
at org.mockito.internal.creation.MethodInterceptorFilter.intercept(MethodInterceptorFilter.java:48)
at org.springframework.jdbc.core.JdbcTemplate$$EnhancerByMockitoWithCGLIB$$92326890.update(<generated>)
at com.test.GenericDaoJdbcImplTestTest$WhenInsertUpdateDeleteIsCalledWith.successfulUpdateShouldReturnTrue(GenericDaoJdbcImplTest.java:197)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
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)
我的GenericDaoJdbcImplTest
是一个抽象类。这是我正在测试的课程。
public abstract class GenericDaoJdbcImpl<MODEL, PRIMARYKEY extends Serializable>
implements GenericJdbcDao<MODEL, PRIMARYKEY> {
@Autowired
@Qualifier(value = "jdbcTemplate")
private JdbcTemplate mJdbcTemplate;
private Class<MODEL> mType;
public JdbcTemplate getJdbcTemplate() {
return mJdbcTemplate;
}
public void setJdbcTemplate(final JdbcTemplate pJdbcTemplate) {
this.mJdbcTemplate = pJdbcTemplate;
}
public GenericDaoJdbcImpl(final Class<MODEL> pType) {
this.mType = pType;
}
public abstract MODEL add(final MODEL mModel);
public abstract MODEL modify(final MODEL mModel);
public abstract MODEL read(PRIMARYKEY pId);
public abstract List<MODEL> list();
public abstract void delete(PRIMARYKEY pId);
@Override
public boolean insertUpdateDelete(final String pSql, final Object[] pArgs,
final int[] pArgTypes) {
Assert.hasLength(pSql, "No SQL provided to execute");
Assert.notNull(pArgs, "No data provided to insert/update/delete");
Assert.notNull(pArgTypes, "No data types provided for");
Assert.isTrue(pArgs.length == pArgTypes.length, "Mis-match in data and data type count");
return (mJdbcTemplate.update(pSql, pArgs, pArgTypes) > 0);
}
}
您必须在when
调用中强制转换参数。否则,参数将不明确,编译器无法将其解析为特定的update
方法。
因此:
Mockito.when(jdbcTemplate.update((String)Mockito.anyString(), (Object[])Mockito.anyVararg())).thenReturn(var);
应该解决您的问题。至少对我来说是这样。
尝试使用ArgumentCaptor
,这些条件往往限制较少,并允许在调用后验证复杂的参数。
@Captor
ArgumentCaptor<Object[]> objCap;
@Captor
ArgumentCaptor<int[]> intCap;
when(mJdbcTemplate.update(anyString(), objCap.capture(), intCap.capture())).thenReturn(1);
不要嘲笑你不拥有的类型这是一大原则。模拟这些类型对测试的负面影响不止一种:
- 它使你的测试复杂化,可能会使它难以制作、阅读、理解或重构
- 你必须了解如何使用这种类型
- 它增强了测试与此实现、版本等的耦合性
- 它给你一种虚假的安全感,因为你已经修改了行为,所以测试通过了,但真正的代码可能已经改变了行为,或者在新版本中看到了新的行为,然后你会看到服务器上的繁荣
在您的情况下,您正在系统的边界上测试一些东西,因此经验法则是在处理数据库等时编写集成测试,并为您的业务代码编写单元测试 我强烈推荐《成长中的面向对象软件——以测试为导向》这本书。我认为这本书可能是帮助编写使用TDD的好软件的最有用的书之一。此外,它是由第一个模拟框架的作者Steve Freeman和Nat Pryce编写的。