如何模拟新的 SimpleJdbcCall
how to mock new SimpleJdbcCall
你能帮我模拟 SimpleJdbcCall 吗?
实际 class 测试如下。
import java.sql.Types;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class HeartBeat {
private static final Logger LOGGER = LogManager.getLogger(HeartBeat.class);
@Autowired
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall jdbcCall;
@PostConstruct
private void applicationStarted() {
LOGGER.info("Application has Started.");
DBCall();
}
@Scheduled(fixedRateString="${application.heartbeatInterval}")
public void sendHeartbeat() {
DBCall();
}
private void DBCall() {
if ( this.jdbcTemplate == null ) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
jdbcTemplate.setResultsMapCaseInsensitive(true);
jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("schema")
.withCatalogName("catalogName")
.withProcedureName("cleanup");
jdbcCall.execute(new HashMap<String, Object>(0));
jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("schema")
.withCatalogName("catalogName")
.withProcedureName("register")
.declareParameters(new SqlParameter("id", Types.VARCHAR))
.declareParameters(new SqlParameter("name", Types.VARCHAR));
MapSqlParameterSource paramMap = new MapSqlParameterSource().addValue("id", "abc").addValue("name", "def");
jdbcCall.execute(paramMap);
}
}
为了测试上面的代码,我创建了
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import java.util.HashMap;
import java.util.Map;
public class HeartBeatTest {
HeartBeat heartBeat;
private JdbcTemplate mockedJdbcTemplate;
private SimpleJdbcCall mockedJdbcCall;
private Map<String, Object> result;
@Before
public void setUp() throws Exception {
this.heartBeatComponent = new HeartBeatComponent();
result = new HashMap<String, Object>();
mockedJdbcTemplate = Mockito.mock(JdbcTemplate.class);
mockedJdbcCall = Mockito.mock(SimpleJdbcCall.class);
Whitebox.setInternalState(heartBeatComponent, "jdbcTemplate",mockedJdbcTemplate);
Whitebox.setInternalState(heartBeatComponent, "jdbcCall",mockedJdbcCall);
// section1
//PowerMockito.whenNew(SimpleJdbcCall.class).withArguments(mockedJdbcTemplate).thenReturn(mockedJdbcCall);
// section2
PowerMockito.whenNew(SimpleJdbcCall.class).withAnyArguments().thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withSchemaName(any(String.class))).thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withCatalogName(any(String.class))).thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withProcedureName(any(String.class))).thenReturn(mockedJdbcCall);
}
@Test
public void sendHeartbeatTest() {
Mockito.when(mockedJdbcCall.execute(anyMap())).thenReturn(result);
Mockito.when(mockedJdbcCall.execute(any(MapSqlParameterSource.class))).thenReturn(result);
heartBeat.sendHeartbeat();
Mockito.verify(mockedJdbcCall, Mockito.times(1)).execute(anyMap());
Mockito.verify(mockedJdbcCall, Mockito.times(1)).execute(any(MapSqlParameterSource.class));
}
}
但它没有按预期工作。我从调试模式可以看到的,
jdbcCall 得到了 mockedJdbcCall 但由于 new SimpleJdbcCall() 以及 .withSchemaName 和其他,它被 simpleJdbcCall 覆盖了。我的期望是当新的 SimpleJdbcCall 被调用时 returns 我设置的 mockedJdbcCall PowerMockito.whenNew...
我试过 PowerMockito.whenNew 的第 1 部分和第 2 部分
我是不是误会了PowerMockito.whenNew?或遗漏了代码中的任何内容?
请指导我。
您需要告诉 PowerMock 您想要在 HeartBeat
class 中模拟 SimpleJdbcCall
class 的构造。尝试将以下注释添加到您的测试 class:
@RunWith(PowerMockRunner.class)
@PrepareForTest(HeartBeat.class)
public class HeartBeatTest {
...
}
你能帮我模拟 SimpleJdbcCall 吗?
实际 class 测试如下。
import java.sql.Types;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class HeartBeat {
private static final Logger LOGGER = LogManager.getLogger(HeartBeat.class);
@Autowired
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall jdbcCall;
@PostConstruct
private void applicationStarted() {
LOGGER.info("Application has Started.");
DBCall();
}
@Scheduled(fixedRateString="${application.heartbeatInterval}")
public void sendHeartbeat() {
DBCall();
}
private void DBCall() {
if ( this.jdbcTemplate == null ) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
jdbcTemplate.setResultsMapCaseInsensitive(true);
jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("schema")
.withCatalogName("catalogName")
.withProcedureName("cleanup");
jdbcCall.execute(new HashMap<String, Object>(0));
jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("schema")
.withCatalogName("catalogName")
.withProcedureName("register")
.declareParameters(new SqlParameter("id", Types.VARCHAR))
.declareParameters(new SqlParameter("name", Types.VARCHAR));
MapSqlParameterSource paramMap = new MapSqlParameterSource().addValue("id", "abc").addValue("name", "def");
jdbcCall.execute(paramMap);
}
}
为了测试上面的代码,我创建了
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import java.util.HashMap;
import java.util.Map;
public class HeartBeatTest {
HeartBeat heartBeat;
private JdbcTemplate mockedJdbcTemplate;
private SimpleJdbcCall mockedJdbcCall;
private Map<String, Object> result;
@Before
public void setUp() throws Exception {
this.heartBeatComponent = new HeartBeatComponent();
result = new HashMap<String, Object>();
mockedJdbcTemplate = Mockito.mock(JdbcTemplate.class);
mockedJdbcCall = Mockito.mock(SimpleJdbcCall.class);
Whitebox.setInternalState(heartBeatComponent, "jdbcTemplate",mockedJdbcTemplate);
Whitebox.setInternalState(heartBeatComponent, "jdbcCall",mockedJdbcCall);
// section1
//PowerMockito.whenNew(SimpleJdbcCall.class).withArguments(mockedJdbcTemplate).thenReturn(mockedJdbcCall);
// section2
PowerMockito.whenNew(SimpleJdbcCall.class).withAnyArguments().thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withSchemaName(any(String.class))).thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withCatalogName(any(String.class))).thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withProcedureName(any(String.class))).thenReturn(mockedJdbcCall);
}
@Test
public void sendHeartbeatTest() {
Mockito.when(mockedJdbcCall.execute(anyMap())).thenReturn(result);
Mockito.when(mockedJdbcCall.execute(any(MapSqlParameterSource.class))).thenReturn(result);
heartBeat.sendHeartbeat();
Mockito.verify(mockedJdbcCall, Mockito.times(1)).execute(anyMap());
Mockito.verify(mockedJdbcCall, Mockito.times(1)).execute(any(MapSqlParameterSource.class));
}
}
但它没有按预期工作。我从调试模式可以看到的, jdbcCall 得到了 mockedJdbcCall 但由于 new SimpleJdbcCall() 以及 .withSchemaName 和其他,它被 simpleJdbcCall 覆盖了。我的期望是当新的 SimpleJdbcCall 被调用时 returns 我设置的 mockedJdbcCall PowerMockito.whenNew...
我试过 PowerMockito.whenNew 的第 1 部分和第 2 部分 我是不是误会了PowerMockito.whenNew?或遗漏了代码中的任何内容?
请指导我。
您需要告诉 PowerMock 您想要在 HeartBeat
class 中模拟 SimpleJdbcCall
class 的构造。尝试将以下注释添加到您的测试 class:
@RunWith(PowerMockRunner.class)
@PrepareForTest(HeartBeat.class)
public class HeartBeatTest {
...
}