如何在 Junit(Spring Boot)中模拟 BeanPropertyRowMapper?
How to mock BeanPropertyRowMapper in Junit (Springboot)?
我正在为电子邮件 DAO 层编写测试用例。类似于:
@Repository
@PropertySource({ "classpath:/query.properties" })
public class DaoLayerImpl implements DaoLayerDao {
/** The jdbc template. */
@Qualifier("mariaJdbcTemplate")
@Autowired
private JdbcTemplate jdbcTemplate;
/** The find staged query. */
@Value("${someQuery}")
String someQuery;
@Override
public List<SomeBean> getData() throws MariaDbException {
List<SomeBean> listOfData = new ArrayList<>();
try {
listOfData = jdbcTemplate.query(someQuery,
new BeanPropertyRowMapper<SomeBean>(SomeBean.class));
} catch (RuntimeException e) {
logger.error("RuntimeException in ", e);
}
return listOfData;
}
}
这一层的测试用例是:
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@PropertySource("classpath:application-test.properties")
public class EmailDaoLayerTest {
@MockBean
JdbcTemplate jdbcTemplate;
@InjectMocks
DaoLayerImpl dao;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
jdbcTemplate = Mockito.mock(JdbcTemplate.someQuery);
ReflectionTestUtils.setField(dao, "jdbcTemplate", jdbcTemplate);
}
@Test
public void testCaseForGetData() throws Exception {
List<SomeBean> beanObject = new ArrayList<>();
beanObject.add(new SomeBean());
beanObject.add(new SomeBean());
beanObject.add(new SomeBean());
System.out.println(beanObject.size()); // 3
when(jdbcTemplate.query("someQuery",
new BeanPropertyRowMapper<SomeBean>(SomeBean.class))).thenReturn(beanObject);
List<SomeBean> obj = dao.getData();
System.out.println(obj.size()); //0
System.out.println("Done");
}
}
模拟后对象大小变为 0 而不是 3。返回前对象的大小为 3。当我实际访问 DAO 时,对象的大小变为 0,而我有已经使用 when-then 模拟了 jdbc 模板。
模拟 Bean 属性 Row Mapper class 的正确方法是什么?
让我回答问题然后批评你的方法,也许这有助于更好地理解解决方案最后应该是什么样子。
所以回答你的问题:
从技术上讲,您可以这样做:
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.any;
...
Mockito.when(jdbcTemplate.query(eq("someQuery"),
any(BeanPropertyRowMapper.class)).thenReturn(....);
但是,您应该问问自己,您到底想在这里测试什么?你在这里有一个相对昂贵的集成测试,运行s Spring 上下文(它与 SpringRunner 一起工作)并在引擎盖下创建许多对象。
然而,根据要测试的方法 - 我没有看到有任何 "meaningful"(待测试)代码要测试。您可以测试给定查询,BeanPropertyRowMapper 确实可以将响应转换为 SomeBean
的实例,但是您再次模拟它并且它实际上并不 运行.
您可以检查您针对数据库准备的查询 运行 和 returns 预期结果,但您似乎没有在这里准备任何数据库。
因此,如果目的是覆盖 - 那么是的,您将被覆盖,但测试与覆盖无关,而是让您 "sure" 确保您的代码正常工作。在这种情况下,运行使用 Spring 驱动集成测试(包含应用程序上下文和所有内容)似乎是一个巨大的矫枉过正,MockitoRunner
可以完成这项工作
我正在为电子邮件 DAO 层编写测试用例。类似于:
@Repository
@PropertySource({ "classpath:/query.properties" })
public class DaoLayerImpl implements DaoLayerDao {
/** The jdbc template. */
@Qualifier("mariaJdbcTemplate")
@Autowired
private JdbcTemplate jdbcTemplate;
/** The find staged query. */
@Value("${someQuery}")
String someQuery;
@Override
public List<SomeBean> getData() throws MariaDbException {
List<SomeBean> listOfData = new ArrayList<>();
try {
listOfData = jdbcTemplate.query(someQuery,
new BeanPropertyRowMapper<SomeBean>(SomeBean.class));
} catch (RuntimeException e) {
logger.error("RuntimeException in ", e);
}
return listOfData;
}
}
这一层的测试用例是:
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@PropertySource("classpath:application-test.properties")
public class EmailDaoLayerTest {
@MockBean
JdbcTemplate jdbcTemplate;
@InjectMocks
DaoLayerImpl dao;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
jdbcTemplate = Mockito.mock(JdbcTemplate.someQuery);
ReflectionTestUtils.setField(dao, "jdbcTemplate", jdbcTemplate);
}
@Test
public void testCaseForGetData() throws Exception {
List<SomeBean> beanObject = new ArrayList<>();
beanObject.add(new SomeBean());
beanObject.add(new SomeBean());
beanObject.add(new SomeBean());
System.out.println(beanObject.size()); // 3
when(jdbcTemplate.query("someQuery",
new BeanPropertyRowMapper<SomeBean>(SomeBean.class))).thenReturn(beanObject);
List<SomeBean> obj = dao.getData();
System.out.println(obj.size()); //0
System.out.println("Done");
}
}
模拟后对象大小变为 0 而不是 3。返回前对象的大小为 3。当我实际访问 DAO 时,对象的大小变为 0,而我有已经使用 when-then 模拟了 jdbc 模板。
模拟 Bean 属性 Row Mapper class 的正确方法是什么?
让我回答问题然后批评你的方法,也许这有助于更好地理解解决方案最后应该是什么样子。
所以回答你的问题:
从技术上讲,您可以这样做:
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.any;
...
Mockito.when(jdbcTemplate.query(eq("someQuery"),
any(BeanPropertyRowMapper.class)).thenReturn(....);
但是,您应该问问自己,您到底想在这里测试什么?你在这里有一个相对昂贵的集成测试,运行s Spring 上下文(它与 SpringRunner 一起工作)并在引擎盖下创建许多对象。
然而,根据要测试的方法 - 我没有看到有任何 "meaningful"(待测试)代码要测试。您可以测试给定查询,BeanPropertyRowMapper 确实可以将响应转换为 SomeBean
的实例,但是您再次模拟它并且它实际上并不 运行.
您可以检查您针对数据库准备的查询 运行 和 returns 预期结果,但您似乎没有在这里准备任何数据库。
因此,如果目的是覆盖 - 那么是的,您将被覆盖,但测试与覆盖无关,而是让您 "sure" 确保您的代码正常工作。在这种情况下,运行使用 Spring 驱动集成测试(包含应用程序上下文和所有内容)似乎是一个巨大的矫枉过正,MockitoRunner
可以完成这项工作