mocking - 无法测试 SimpleJdbcCall 执行调用
问题描述
我需要测试以下课程
@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();
}
}
}
我的测试类
@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);
}
}
得到以下异常
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)
我试过了
@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)
解决方案
正如评论中所暗示的那样,您的异常可能来自试图在非模拟的东西上定义行为。
假设您的代码看起来像这样(更改后):
@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
与 the 一起使用MockitoJUnitRunner
不会产生任何影响。Mockito
您需要做的是在您的JdbcTemplate
模拟上定义行为,以便它
SimpleJdbcCall
可以正常工作。我简要查看了 spring 源代码,并根据我所看到的(至少)定义call
方法中使用的AbstractJdbcCall#executeCallInternal
方法的行为。
所以把测试改成这样可能会奏效......
@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);
}
}
注意:模拟 aMap
从来都不是真正必要的。相反,只需创建一个地图并将所需的内容添加到其中。
然而,更简单的方法是重构类,以便您可以简单地替换新创建的SimpleJdbcCall
. 您的示例代码显示了一个SimpleJdbcCallFactory
创建此类对象的类,但似乎与您的测试类没有任何关系。
如果重构不是使用PowerMockito.whenNew
功能的选项,我们可能也值得考虑。
就是说-最后我建议您宁愿专注于带有real
数据库的集成测试,而不是在这里使用模拟。
推荐阅读
- reactjs - React 和 Entity Framework Core Web API 的 CORS 问题
- java - 在 MVC 中使用 js 和 jsp 发布请求
- winapi - 强制 Win32 常用控件在“ID2D1HwndRenderTarget”上绘制?
- yii2 - Yii2 Assest Bundle 未在视图中加载 CSS
- java - 将属性存储在实例变量中还是使用方法计算?
- javascript - 如何在 HTML 中绘制多个变量的两个输入
- javascript - Apigee HMAC 摘要和 base64 编码
- vb.net - WCF 服务错误“已超出传入消息的最大消息大小配额”
- flutter - 如何将过期时间添加到颤动的 Web cookie?
- python - 如何将不同长度和形状的数组相乘?