SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource);
2.1.2 queryForInt
The query is expected to be a single row/single column query that results in an int value.
String sql = "SELECT COUNT(1) FROM bmw_users";
int result = jdbcTemplate.queryForInt(sql);
2.1.3 queryForList
The results will be mapped to a List (one entry for each row) of Maps (one entry for each column, using the column name as the key).
String sql = "SELECT * FROM bmw_users WHERE city=? AND user_gender=? ";
List<Map> resutls = jdbcTemplate.queryForList(sql, "杭州","m");
2.1.4 query
like queryForList but mapping each row to a Java object
String sql = "SELECT user_id userId,nick,user_gender sex FROM bmw_users WHERE city=? AND user_gender=?";
List resutls = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(User.class),"杭州","m");
2.1.5 update or delete data
String sql = "DELETE FROM bmw_users WHERE id=? ";
jdbcTemplate.update(sql, “1111”);
对SimpleJdbcTemplate的介绍就到这里,更多的用法可参考其JavaDoc或源码。
2.2 思考&实践
由于测试过程中用到的sql不会很复杂,我们利用SimpleJdbcTemplate可以封装一些常用的操作,在用例代码中甚至不需要编写sql语句即可完成数据库操作。下面的例子展示了运用封装的JdbcTestUtil根据条件查询某表的数据。Map args = new HashMap();
args.put("nick", "tbtest561");
List results = JdbcTestUtil.queryData(jdbcTemplate, "bmw_users", args);
JdbcTestUtil的更多用法可参考svn…
3 TestContext
TestContext本来是为了测试基于Spring的应用程序而开发的,其实在非Spring程序测试中一样可以运用它,方便的解决配置等问题,而且 其提供的监听器机制为我们自定义工具对用例运行进行细微控制提供了良好的思路。下面通过简单的示例入手,接着通过分析源码,找出了可为我们所用的扩展点。
3.1 合理准备配置文件
这个在基类文件中引入,子类配置会自动继承。这是个最大化的文件,基本包含了所有声明。 。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
default-lazy-init="true">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<!-- 使用annotation 自动注册bean -->
<context:component-scan base-package="com.taobao"/>
<context:annotation-config />
</beans>
Jdbc配置信息统一在一个文件里,方便维护。
jdbc.driverClassName=oracle.jdbc.OracleDriver
dev-db1.jdbc.url=jdbc:oracle:thin:@192.168.205.37:1521:dev-db1
taobao.jdbc.username=taobao
taobao.jdbc.password=taobao
dev-dbc.jdbc.url=jdbc:oracle:thin:@192.168.205.37:1521:dev-dbc
tbcat.jdbc.username=tbcat
tbcat.jdbc.password=tbcat
我们测试项目需要多个数据源,但一个测试类一般只需要一个,因此建议每个数据源一个配置文件,用例类只需引入自己相关的配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="itemDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${dev-db1.jdbc.url}"/>
<property name="username" value="${taobao.jdbc.username}"/>
<property name="password" value="${taobao.jdbc.password}"/>
</bean>
</beans>
3.2 简单应用示例 @ContextConfiguration(locations = { "classpath:applicationContext.xml" })//①
public class BaseCase extends AbstractJUnit4SpringContextTests {//②
}
@ContextConfiguration(locations = { "classpath:datasource-item.xml" })//③
public class ItemAddTest extends BaseCase {
private SimpleJdbcTemplate jdbcTemplate;
@Autowired//④
public void init(DataSource dataSource) {
jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
}
上面的示例对TestContext的应用非常简单,归纳起来就是一个基类两个注解。
一个基类:AbstractJUnit4SpringContextTests,如②,如果你测试的业务支持事务,可继承AbstractTransactionalJUnit4SpringContextTests,同时在配置文件里加上事务控制相关内容。 注解一:用@ContextConfiguration引入Spring配置文件。TestContext根据这个配置文件启动Spring容器。我们可在基类引入基础配置文件如①,在子类只引入相关的配置文件如③ 注解二:通过@Autowired自动装配Bean,如④。
当 Spring 容器启动时,将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有 @Autowired 注释时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。
如果容器中配置了类型相同的多个Bean,可用@Qualifier指定名称,例如如果类中引入了多个数据源,其示例代码如下 @Autowired
另外@Autowired还可标注于成员变量和构造器,例如如果配置了要测试的类TaobaoDirectJsonRestClient,可通过下面的方法实例化。
public void init(@Qualifier("itemDataSource")
DataSource dataSource) {
jdbcTemplateItem = new SimpleJdbcTemplate(dataSource);
}
@Autowired
public void init2(@Qualifier("userDataSource")
DataSource dataSource) {
jdbcTemplateUser = new SimpleJdbcTemplate(dataSource);
}@Autowired
private TaobaoDirectJsonRestClient client;
3.3 源码分析
在上面的示例中我们通过继承AbstractJUnit4SpringContextTests和@ContextConfiguration标注就完成了Spring容器的启动和与Junit的结合,下面我们通过源码分析更进一步了解其深层原理。
AbstractJUnit4SpringContextTests的骨干代码如下:@RunWith(SpringJUnit4ClassRunner.class)//①
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})//②
public abstract class AbstractJUnit4SpringContextTests implements ApplicationContextAware {
在②处的标注跟Junit没啥关系,我们先看①处的@RunWith, Junit4中广泛使用测试运行器,通过@RunWith注解告诉Junit采用何种运行器,事实上如果没有指定@RunWith,那么测试类仍然会使用 一个默认运行器 (org.junit.internal.runners.TestClassRunner,继承于JUnit4ClassRunner)执行,我们继续 看SpringJUnit4ClassRunner做了什么。SpringJUnit4ClassRunner核心代码如下:public class SpringJUnit4ClassRunner extends JUnit4ClassRunner {
private final TestContextManager testContextManager;
@Override
protected Object createTest() throws Exception {
Object testInstance = super.createTest();
getTestContextManager().prepareTestInstance(testInstance);// ③
return testInstance;
}
//这里忽略了其他非关键代码
}
SpringJUnit4ClassRunner同样继承了JUnit4ClassRunner,主要覆盖了其createTest方法,在 createTest方法里利用TestContextManager对testInstance进行处理。继续再看看 TestContextManager的关键代码。public class TestContextManager {
private final TestContext testContext;// ④
private final List testExecutionListeners = new ArrayList(); //⑤,与前面的②呼应
至此脉络大致清晰,对Spring TestContext核心类总结如下:
SpringJunit4ClassRunner:Junit4运行器(见①),是Spring TestContext与Junit4结合的根本。 TestContext:封装了运行测试用例的上下文。 TestContextManager:Spring TestContext的主入口点, 管理TestContext(见④)和TestExecutionListener(见⑤) TestExecutionListener:负责响应TestContextManager发布的事件,执行具体的操作,其中常用的Listener见②。3.4 思考&实践
Spring TestContext本身运用是比较简单的,只需要准备配置文件、继承它提供的抽象类以及掌握几个注解即可。另外,通过源码分析我们发现了两个可扩展点,如果有必要可以利用这些扩展点在不改变其程序的情况下,开发符合我们自己需求的工具类。
在我的下篇博文-Managing test data with DbUnit And @XDataSet 里展示了运用扩展点二定制一个监听器,该监听器负责根据测试类或方法中的注解完成测试数据的准备和清理,具有支持多数据源及多种类型的数据集如XLS、XML等特性。
4 小结
本文通过简单的示例说明了如何在接口测试中应用Spring的JdbcTemplate和TestContext,最后通过源码分析发现了两个可扩展点, 为量身定做符合自己的测试工具找到了入口点。关于对其中一个扩展点TestExecutionListener的实践应用请关注我的下篇博文-Managing test data with DbUnit And @XDataSet 。