首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >无法测试SimpleJdbcCall执行调用

无法测试SimpleJdbcCall执行调用
EN

Stack Overflow用户
提问于 2019-12-10 12:40:13
回答 1查看 2.2K关注 0票数 0

我需要测试下一节课

代码语言:javascript
运行
复制
@Repository
public class CustomerContactDaoImpl implements CustomerContactDao {
    @Autowired
    @Qualifier(value = "rcx_jdbc_template")
    private JdbcTemplate jdbcTemplate;
    @Override
    public void insertCustomerContact(Contact contact) {
        SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_contact");
        try {
            call.execute(new MapSqlParameterSource().addValue("customerid", contact.getCustomerID()));

        } catch (Exception e) {
            e.printStackTrace();
        }


    }

}

MyTest类

代码语言:javascript
运行
复制
@RunWith(MockitoJUnitRunner.class)
public class CustContDaoImplTest {
     @Mock
       private SimpleJdbcCallFactory simpleJdbcCallFactory;
     @Mock
       private DataSource dataSource;
     @Mock
       private JdbcTemplate jdbcTemplate;
     @Autowired
     @InjectMocks
       private CustomerContactDaoImpl customerContactDaoImpl;
     @Before
     public void setUp() throws SQLException {
      MockitoAnnotations.initMocks(this);
     }

     @Test
       public void testinsertCustomerContact() throws Exception {
           Contact contact = Mockito.mock(Contact.class);
            SimpleJdbcCall mockedSimpleJdbcCall  = Mockito.mock(SimpleJdbcCall.class);
            mockedSimpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_contact");
            Mockito.when(mockedSimpleJdbcCall.execute(any(MapSqlParameterSource.class))).thenReturn(any(Map.class));
            customerContactDaoImpl.insertCustomerContact(contact);
       }
}

@Component
class SimpleJdbcCallFactory {
   public SimpleJdbcCall create(JdbcTemplate template) {
       return new SimpleJdbcCall(template);
   }
}

获取以下异常

代码语言:javascript
运行
复制
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> dao.test.CustContDaoImpl.testinsertCustomerContact(CustContDaoImpl.java:68)



    at org.springframework.jdbc.core.simple.AbstractJdbcCall.compile(AbstractJdbcCall.java:283)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.checkCompiled(AbstractJdbcCall.java:348)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:363)
    at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:198)
    atdao.test.CustContDaoImpl.testinsertCustomerContact(CustContDaoImpl.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

我试过

代码语言:javascript
运行
复制
@RunWith(MockitoJUnitRunner.class)
public class CustContDaoImplTest {
     @Mock
       private SimpleJdbcCallFactory simpleJdbcCallFactory;
     @Mock
       private DataSource dataSource;
     @Mock
       private JdbcTemplate jdbcTemplate;

     @InjectMocks
       private CustomerContactDaoImpl customerContactDaoImpl;

     @Before
     public void setUp() throws SQLException {
      MockitoAnnotations.initMocks(this);
     }

     @Test
       public void testinsertCustomerContact() throws Exception {
           Contact contact = Mockito.mock(Contact.class);
            Map<String, Object> resMap = new HashMap<>();
            Mockito.when(jdbcTemplate.call(Mockito.any(), Mockito.any())).thenReturn(resMap);
            customerContactDaoImpl.insertCustomerContact(contact);
     }
}

java.lang.IllegalArgumentException: No DataSource specified
    at org.springframework.util.Assert.notNull(Assert.java:115)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:97)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
    at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:289)
    at org.springframework.jdbc.core.metadata.CallMetaDataProviderFactory.createMetaDataProvider(CallMetaDataProviderFactory.java:73)
    at org.springframework.jdbc.core.metadata.CallMetaDataContext.initializeMetaData(CallMetaDataContext.java:286)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.compileInternal(AbstractJdbcCall.java:303)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.compile(AbstractJdbcCall.java:288)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.checkCompiled(AbstractJdbcCall.java:348)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:363)
    at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:198)
    at com.nrg.bccd.dao.impl.CustomerContactDaoImpl.insertCustomerContact(CustomerContactDaoImpl.java:65)
     dao.test.CustContDaoImplTest.testinsertCustomerContact(CustContDaoImplTest.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
EN

回答 1

Stack Overflow用户

发布于 2019-12-10 18:49:39

正如评论中所暗示的那样,您的异常很可能来自于尝试定义非模拟的行为。

假设您的代码看起来如下(在您的更改之后):

代码语言:javascript
运行
复制
@Test
public void testinsertCustomerContact() throws Exception {
    Contact contact = Mockito.mock(Contact.class);

    SimpleJdbcCall mockedSimpleJdbcCall = Mockito.mock(SimpleJdbcCall.class);

    // this line is causing the problem
    mockedSimpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_contact");

    Map<String, Object> resMap = Mockito.mock(Map.class);
    Mockito.when(mockedSimpleJdbcCall.execute(any(MapSqlParameterSource.class))).thenReturn(resMap); 

    customerContactDaoImpl.insertCustomerContact(contact);
}

然后,当您创建一个新的SimpleJdbcCall对象时,仍然要重写模拟。

然而,所有这些似乎都不是正确的方法,因为它与您的测试中的类不匹配。

@Autowired / @Component中使用MockitoJUnitRunner不会产生任何效果,因为Mockito不知道这些注释。

您需要做的是定义您的JdbcTemplate模拟上的行为,以便SimpleJdbcCall能够正常工作。我简短地看了一下spring源代码,并根据我所看到的,您需要(至少)在call方法上定义行为,这是在AbstractJdbcCall#executeCallInternal方法中使用的。

所以把测试变成这样也许会有效果..。

代码语言:javascript
运行
复制
@RunWith(MockitoJUnitRunner.class)
public class CustContDaoImplTest {

    @Mock
    private JdbcTemplate jdbcTemplate;

    @InjectMocks
    private CustomerContactDaoImpl customerContactDaoImpl;

    @Before
    public void setUp() throws SQLException {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testinsertCustomerContact() throws Exception {

        Contact contact = Mockito.mock(Contact.class);

        Map<String, Object> resMap = new HashMap<>();
        Mockito.when(jdbcTemplate.call(Mockito.any(), Mockito.any())).thenReturn(resMap);

        customerContactDaoImpl.insertCustomerContact(contact);
    }
}

注意:模拟Map并不是真正必要的。相反,只需创建一个映射并将所需的内容添加到其中。

然而,一种更简单的方法是重构类,这样您就可以简单地替换新创建的SimpleJdbcCall实例。示例代码显示了一个创建这样一个对象的SimpleJdbcCallFactory类,但是似乎与被测试的类没有任何关系。

如果重构不是使用PowerMockito.whenNew功能的一种选择,那么我们也应该考虑。

这就是说--最后,我建议您将重点放在后面有一个real数据库的集成测试上,而不是在这里使用模拟。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59267453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档