在模拟JDBCTemplate时,未获得任何数据源指定的错误

时间:2019-11-27 18:03:00

标签: mocking mockito

我正在为以下方法编写TestCase

@Repository
public class CustomerContactDaoImpl implements CustomerContactDao {
    @Autowired
    @Qualifier(value = "dcv_jdbc_template")
    private JdbcTemplate jdbcTemplate;
    @Override
    public void insertCustomer(Contact contact) {
        SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate).withProcedureName("ins_customerinfo");
                try {
            call.execute(new MapSqlParameterSource().addValue("customerid", contact.getCustomerID())));
    } catch (Exception e) {}
}

这是我的测试用例

@RunWith(PowerMockRunner.class)
public class CustomerContactDaoImplTest {
    @InjectMocks
    CustomerContactDaoImpl customerContactDaoImpl;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

      @Test
       public void insertCustomerContactTest() throws Exception {
        Contact contact = Mockito.mock(Contact.class);
        JdbcTemplate jdbcTemplateMock = Mockito.mock(JdbcTemplate.class);
        SimpleJdbcCall mockedSimpleJdbcCall = Mockito.mock(SimpleJdbcCall.class);
        PowerMockito.whenNew(SimpleJdbcCall.class).withArguments(jdbcTemplateMock).thenReturn(mockedSimpleJdbcCall);
        mockedSimpleJdbcCall.execute(new MapSqlParameterSource().addValue("customerid", contact.getCustomerID())));
       customerContactDaoImpl.insertCustomerContact(contact);
}

}

我收到错误消息

当模拟JDBCTemplate时,未获得未指定数据源的错误

请让我知道如何解决此错误

org.powermock.reflect.exceptions.TooManyConstructorsFoundException: Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're referring to.
Matching constructors in class org.springframework.jdbc.core.simple.SimpleJdbcCall were:
org.springframework.jdbc.core.simple.SimpleJdbcCall( javax.sql.DataSource.class )
org.springframework.jdbc.core.simple.SimpleJdbcCall( org.springframework.jdbc.core.JdbcTemplate.class )

    at org.powermock.reflect.internal.WhiteboxImpl.throwExceptionWhenMultipleConstructorMatchesFound(WhiteboxImpl.java:1723)
    at org.powermock.reflect.internal.WhiteboxImpl.findUniqueConstructorOrThrowException(WhiteboxImpl.java:1097)
    at org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.createNewSubstituteMock(DefaultConstructorExpectationSetup.java:94)
    at org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.withArguments(DefaultConstructorExpectationSetup.java:54)
    at com.nrg.bccd.dao.test.CustomerContactDaoImplTest.insertCustomerContactTest(CustomerContactDaoImplTest.java:71)
    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.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)

2 个答案:

答案 0 :(得分:4)

紧密耦合使得很难在没有意外行为的情况下隔离测试此代码。

但是让我们在当前状态下进行测试。

@InjectMocks被使用,

@InjectMocks
CustomerContactDaoImpl customerContactDaoImpl;

但是在测试中声明了手动模拟

JdbcTemplate jdbcTemplateMock = Mockito.mock(JdbcTemplate.class);

并用作参数匹配器

PowerMockito.whenNew(SimpleJdbcCall.class).withArguments(jdbcTemplateMock).thenReturn(mockedSimpleJdbcCall);

由于设置new SimpleJdbcCall(...时使用的实例不是在进行测试时注入的实例,因此参数将不匹配,并且将创建SimpleJdbcCall的实际实例,并且它将尝试使用嘲笑的JdbcTemplate(而不是您嘲笑的那个)和bam,错误。

需要对测试进行重构,以验证运动后的预期行为。

@RunWith(PowerMockRunner.class)
@PrepareForTest(CustomerContactDaoImpl.class) //prepare the class creating the new instance
public class CustomerContactDaoImplTest {

    @Mock
    JdbcTemplate jdbcTemplateMock; //YOUR MOCK TO BE INJECTED

    @InjectMocks
    CustomerContactDaoImpl customerContactDaoImpl;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void insertCustomerContactTest() throws Exception {
        //Arrange
        string paramName = "customerid";
        string expected = "fakeCustomerIdHere"; //assumption made as to type;
        Contact contact = Mockito.mock(Contact.class);
        when(contact.getCustomerID()).thenReturn(expected);

        SimpleJdbcCall mockedSimpleJdbcCall = Mockito.mock(SimpleJdbcCall.class);
        when(mockedSimpleJdbcCall.withProcedureName(anyString()))
            .thenReturn(mockedSimpleJdbcCall);

        PowerMockito.whenNew(SimpleJdbcCall.class).withArguments(jdbcTemplateMock)
            .thenReturn(mockedSimpleJdbcCall);

        //Act
        customerContactDaoImpl.insertCustomerContact(contact);

        //Assert
        verify(mockedSimpleJdbcCall).execute(any(MapSqlParameterSource.class));
        verify(contact).getCustomerID();
    }
}

答案 1 :(得分:0)

遵循Spring JDBC tests,首先模拟所有数据库对象:

@BeforeEach
public void setUp() throws Exception {
    connection = mock(Connection.class);
    databaseMetaData = mock(DatabaseMetaData.class);
    dataSource = mock(DataSource.class);
    callableStatement = mock(CallableStatement.class);
    given(connection.getMetaData()).willReturn(databaseMetaData);
    given(dataSource.getConnection()).willReturn(connection);
}

并在测试中使用它们:

@Test
public void testAddInvoiceProcWithoutMetaDataUsingMapParamSource() throws Exception {
    initializeAddInvoiceWithoutMetaData(false);
    SimpleJdbcCall adder = new SimpleJdbcCall(dataSource).withProcedureName("add_invoice");
    adder.declareParameters(
            new SqlParameter("amount", Types.INTEGER),
            new SqlParameter("custid", Types.INTEGER),
            new SqlOutParameter("newid", Types.INTEGER));
    Number newId = adder.executeObject(Number.class, new MapSqlParameterSource().
            addValue("amount", 1103).
            addValue("custid", 3));
    assertThat(newId.intValue()).isEqualTo(4);