将JdbcTemplate更新方法与Mockito匹配

时间:2013-07-17 08:40:27

标签: java junit junit4 mockito

我正在尝试匹配我在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);
    }
}

3 个答案:

答案 0 :(得分:3)

您必须在when调用中强制转换参数。否则,参数将变得模棱两可,并且编译器无法将其解析为特定的update方法。

所以:

Mockito.when(jdbcTemplate.update((String)Mockito.anyString(), (Object[])Mockito.anyVararg())).thenReturn(var);

应该解决您的问题。至少对我有用。

答案 1 :(得分:2)

尝试使用ArgumentCaptor,这些条件的限制性较小,并允许在调用后验证复杂的参数。

@Captor
ArgumentCaptor<Object[]> objCap;
@Captor
ArgumentCaptor<int[]> intCap;

when(mJdbcTemplate.update(anyString(), objCap.capture(), intCap.capture())).thenReturn(1);

答案 2 :(得分:1)

不要嘲笑你不拥有的类型!这是一个很重要的原则。模拟这些类型对测试的负面影响不仅仅是一种方式:

  1. 它使您的测试变得复杂,可能使其难以制作,阅读,理解或重构
  2. 您必须了解如何使用此类型。
  3. 它增强了测试与此实现,版本等的耦合
  4. 它给你一种虚假的安全感,因为你已经改变了行为,所以测试正在通过,但真正的代码可能已经改变了行为或看到了新版本的新行为,然后你会看到一个繁荣在服务器上!
  5. 在你的情况下,你正在系统的边界测试一些东西,所以拇指规则是在处理数据库等时编写集成测试并编写单元测试用于您的业务代码。

    我强烈推荐Growing Object Oriented Software - Guided by tests本书。我认为这可能是帮助使用TDD编写优秀软件的最有用的书之一。此外,它还由第一个模拟框架的作者 Steve Freeman Nat Pryce 撰写。