Spring在接口测试中的应用

1 引言
本文旨在介绍Spring的JdbcTemplate和TestContext,希望通过简单的示例可以使初学者能够快速上手,在项目测试中灵活运用。
2 SimpleJdbcTemplate
在很多测试中需要访问数据库验证业务逻辑,你正在使用什么工具?Spring的SimpleJdbcTemplate是个不错的选择。该工具封装了常用的 Jdbc操作,其中一个很方便的特性是其会迭代查询的ResultSet结果集为方便操作的java对象。下面通过简单的示例说明其用法。
2.1 简单应用示例

  • 2.1.1 Construct new instance
    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 合理准备配置文件

  • 3.1.1 基本配置文件(src/test/resources/applicationContext.xml)
    这个在基类文件中引入,子类配置会自动继承。这是个最大化的文件,基本包含了所有声明。

    <?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>

  • 3.1.2 Jdbc配置文件(src/test/resources/jdbc.properties)
    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

  • 3.1.3 数据源配置文件示例(src/test/resources/datasource-item.xml)
    我们测试项目需要多个数据源,但一个测试类一般只需要一个,因此建议每个数据源一个配置文件,用例类只需引入自己相关的配置文件。
    <?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
    public void init(@Qualifier("itemDataSource")
    DataSource dataSource) {
    jdbcTemplateItem = new SimpleJdbcTemplate(dataSource);
    }
    @Autowired
    public void init2(@Qualifier("userDataSource")
    DataSource dataSource) {
    jdbcTemplateUser = new SimpleJdbcTemplate(dataSource);
    }
    另外@Autowired还可标注于成员变量和构造器,例如如果配置了要测试的类TaobaoDirectJsonRestClient,可通过下面的方法实例化。
    @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本身运用是比较简单的,只需要准备配置文件、继承它提供的抽象类以及掌握几个注解即可。另外,通过源码分析我们发现了两个可扩展点,如果有必要可以利用这些扩展点在不改变其程序的情况下,开发符合我们自己需求的工具类。

  • 扩展点一:Junit4提供的测试运行器机制。可编写自己的测试运行器类,该类应继承JUnit4ClassRunner,覆盖其关键的方法。
  • 扩展点二:Spring TestContext提供的TestExecutionListener机制。可编写自己的测试执行监听器,该类应实现TestExecutionListener接口。
  • 在我的下篇博文-Managing test data with DbUnit And @XDataSet 里展示了运用扩展点二定制一个监听器,该监听器负责根据测试类或方法中的注解完成测试数据的准备和清理,具有支持多数据源及多种类型的数据集如XLS、XML等特性。
    4 小结
    本文通过简单的示例说明了如何在接口测试中应用Spring的JdbcTemplate和TestContext,最后通过源码分析发现了两个可扩展点, 为量身定做符合自己的测试工具找到了入口点。关于对其中一个扩展点TestExecutionListener的实践应用请关注我的下篇博文-Managing test data with DbUnit And @XDataSet

    VN:F [1.9.6_1107]
    Rating: 10.0/ 10 (2 votes cast)
    Spring在接口测试中的应用 , 10.0 out of 10 based on 2 ratings 转载务必注明出处 Taobao QA Team

    你可能感兴趣的:(spring,AOP,sql,bean,jdbc)