天天看点

《我要进大厂系列 五》-谈谈你常用的测试框架有哪些?

文章目录

  • ​​1.Junit的使用​​
  • ​​1.1.Junit 是什么​​
  • ​​1.2.Junit 能做什么​​
  • ​​1.3.Junit 的用法​​
  • ​​1.4 单元测试小结​​
  • ​​1.5 Unit4新断言-Hamcrest的常用方法​​
  • ​​1.5.1.字符相关匹配符​​
  • ​​1.5.2.一般匹配符​​
  • ​​1.5.3.数值相关匹配符​​
  • ​​1.5.4.集合相关匹配符​​
  • ​​1.6 Unit4新断言-Hamcrest的常用方法​​
  • ​​2.2. Stub(桩)的使用​​
  • ​​3.dbunit的使用​​
  • ​​4.EasyMock的使用 -测试业务逻辑层​​
  • ​​5.SpringTest使用​​

1.Junit的使用

1.1.Junit 是什么

JUnit是一个Java语言的​

​单元测试​

​​框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。

注意:Junit 测试也是程序员测试,即所谓的白盒测试,它需要程序员知道被测试的代码如何完成功能,以及完成什么样的功能。

白盒测试:  Junit 测试也是程序员测试,即所谓的白盒测试 程序内部细节
黑盒测试:  只需要测试功能好不好用      

1.2.Junit 能做什么

我们知道 Junit 是一个单元测试框架,那么使用 Junit 能让我们快速的完成单元测试。

通常我们写完代码想要测试这段代码的正确性,那么必须新建一个类,然后创建一个 main() 方法,然后编写测试代码。如果需要测试的代码很多呢?那么要么就会建很多main() 方法来测试,要么将其全部写在一个 main() 方法里面。这也会大大的增加测试的复杂度,降低程序员的测试积极性。而 Junit 能很好的解决这个问题,简化单元测试,写一点测一点,在编写以后的代码中如果发现问题可以较快的追踪到问题的原因,减小回归错误的纠错难度。

1.3.Junit 的用法

 首先下载 Junit jar 包

<!-- Junit -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
</dependency>      

 我们先看下面这个例子,看一下 Junit 的用法

①、编写代码(需要测试的类)

public class Calculator {

  /**
   * 传入两个参数,求和
   * @param a
   * @param b
   * @return
   */
  public int add(int a, int b) {

    return a + b;
  }

  /**
   * 传入两个参数,求差
   * @param a
   * @param b
   * @return
   */
  public int sub(int a, int b) {

    return a - b;
  }
}      

②、编写测试类

 不用Junit

public class CalculatorTest {

  public static void main(String[] args) {
    Calculator c = new Calculator();
    // 测试 add()方法
    int result = c.add(1, 2);
    if (result == 3) {
      System.out.println("add()方法正确");
    }

    // 测试 sub()方法
    int result2 = c.sub(2, 1);
    if (result2 == 1) {
      System.out.println("sub()方法正确");
    }
  }
}      

那么我们可以看到,不用 Junit 只能写在 main()方法中,通过运行结果来判断测试结果是否正确。这里需要测试的只有两个方法,如果有很多方法,那么测试代码就会变得很混乱。

 使用 Junit(看不懂 Assert.assertEquals()方法没关系,可以自己写 if()语句来判断)

public class CalculatorTest1 {

  @Test
  // 测试 add()方法
  public void testAdd() {
    Calculator c = new Calculator();
    int result = c.add(1, 2);
    Assert.assertEquals(result, 3);
  }

  @Test
  // 测试 sub()方法
  public void testSub() {
    Calculator c = new Calculator();
    int result = c.sub(2, 1);
    Assert.assertEquals(result, 1);
  }
}      

那么由上面可以看到,使用 Junit 不需要创建 main() 方法,而且每个测试方法一一对应,逻辑特别清晰。可能有读者会问,这样写代码量也并不会减少啊,那么你接着往下看:

首先介绍 Junit 的几种类似于 @Test 的注解:

  1.@Test: 测试方法

   a)(expected=XXException.class)如果程序的异常和XXException.class一样,则测试通过

   b)(timeout=100)如果程序的执行能在100毫秒之内完成,则测试通过

  2.@Ignore: 被忽略的测试方法:加上之后,暂时不运行此段代码

  3.@Before: 每一个测试方法之前运行

  4.@After: 每一个测试方法之后运行

  5.@BeforeClass: 方法必须必须要是静态方法(static 声明),所有测试开始之前运行,注意区分before,是所有测试方法

6.@AfterClass: 方法必须要是静态方法(static 声明),所有测试结束之后运行,注意区分 @After

那么上面的例子,我们可以看到,每个 @Test 方法中都有 Calculator c = new Calculator();即类的实例化,那么我们可以将其放入到 @Before 中

public class JunitTest {

  public JunitTest() {
    System.out.println("构造函数");
  }

  @BeforeClass
  public static void beforeClass() {
    System.out.println("@BeforeClass");
  }

  @Before
  public void befor() {
    System.out.println("@Before");
  }

  @Test
  public void test() {
    System.out.println("@Test");
  }

  @Ignore
  public void ignore() {
    System.out.println("@Ignore");
  }

  @After
  public void after() {
    System.out.println("@After");
  }

  @AfterClass
  public static void afterClass() {
    System.out.println("@AfterClass");
  }
}      

注意:编写测试类的原则: 

   ①测试方法上必须使用@Test进行修饰

②测试方法必须使用public void 进行修饰,不能带任何的参数

③新建一个源代码目录来存放我们的测试代码,即将测试代码和项目业务代码分开

④测试类所在的包名应该和被测试类所在的包名保持一致

⑤测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖

⑥测试类使用Test作为类名的后缀(不是必须)

⑦测试方法使用test作为方法名的前缀(不是必须)

 测试类测试

public class TestCalture {
  //第一步:应该维护Calture的这个对象
  private Calture calture=null;
  //第二步:初始化对象以及数据
  
  @Before             //类的对象初始化的时候 进行调用 (这个使用的比较多)
  //@BeforeClass      //这个注解是在 类的对象初始化之前 进行调用了  也就是说 对象还没有存在就被调用了
  public void init(){
    calture=new Calture();
  }
  
  @Test
  public void testAdd() throws Exception {
    //下面就进行操作了
    int acResult=calture.add(1,1);
    //接下来进行断言
    assertNotNull(acResult);
    assertEquals(2,acResult);
    //假设要进行10次断言呢?
    //assert这个家伙就要写10次
  }
  
  @Test(expected=ArithmeticException.class,timeout=3000)  //当我们知道要产生异常的时候可以使用expected 来告诉虚拟机希望产生怎样一个异常
  public void testCf(){
    int acResult=calture.chu(1,0);
  }
  
  @After
  public void destory(){
    calture=null;
  }
}      

1.4 单元测试小结

单元测试的用处到底是什么?

 对当前的这个模块的功能进行测试

 回归测试的时候检查当前开发的功能和前面已经完成的功能是否产生了影响

1.5 Unit4新断言-Hamcrest的常用方法

1.5.1.字符相关匹配符

1、equalTo:

assertThat(testedValue, equalTo(expectedValue));

断言被测的testedValue等于expectedValue,equalTo可以断言数值之间,字符串之间和对象之间是否相等,相当于Object的equals方法

2、equalToIgnoringCase:

assertThat(testedString, equalToIgnoringCase(expectedString));

断言被测的字符串testedString在忽略大小写的情况下等于expectedString

3、equalToIgnoringWhiteSpace:

assertThat(testedString, equalToIgnoringWhiteSpace(expectedString);

断言被测的字符串testedString在忽略头尾的任意个空格的情况下等于expectedString

(注意:字符串中的空格不能被忽略)

4、containsString:

assertThat(testedString, containsString(subString) );

断言被测的字符串testedString包含子字符串subString

5、endsWith:

assertThat(testedString, endsWith(suffix));

断言被测的字符串testedString以子字符串suffix结尾

6、startsWith:

assertThat(testedString, startsWith(prefix));

断言被测的字符串testedString以子字符串prefix开始

1.5.2.一般匹配符

1、nullValue():

assertThat(object,nullValue());

断言被测object的值为null

2、notNullValue():

assertThat(object,notNullValue());

断言被测object的值不为null

3、is:

assertThat(testedString, is(equalTo(expectedValue)));

断言被测的object等于后面给出匹配表达式

1)is匹配符简写应用之一:

assertThat(testedValue, is(expectedValue));

is(equalTo(x))的简写,断言testedValue等于expectedValue

2)is匹配符简写应用之二:

assertThat(testedObject, is(Cheddar.class));

is(instanceOf(SomeClass.class))的简写,断言testedObject为Cheddar的实例

4、not:

assertThat(testedString, not(expectedString));

与is匹配符正好相反,断言被测的object不等于后面给出的object

5、allOf:

assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );

断言符合所有条件,相当于“与”(&&)

6、anyOf:

assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );

断言符合条件之一,相当于“或”(||)

1.5.3.数值相关匹配符

1、closeTo:

assertThat(testedDouble, closeTo( 20.0, 0.5 ));

断言被测的浮点型数testedDouble在20.0-0.5 ~ 20.0+0.5范围之内

2、greaterThan:

assertThat(testedNumber, greaterThan(16.0));

断言被测的数值testedNumber大于16.0

3、lessThan:

assertThat(testedNumber, lessThan (16.0));

断言被测的数值testedNumber小于16.0

4、greaterThanOrEqualTo:

assertThat(testedNumber, greaterThanOrEqualTo (16.0));

断言被测的数值testedNumber大于等于16.0

5、lessThanOrEqualTo:

assertThat(testedNumber, lessThanOrEqualTo (16.0));

断言被测的testedNumber小于等于16.0

1.5.4.集合相关匹配符

1、hasEntry:

assertThat(mapObject, hasEntry(“key”, “value” ) );

断言被测的Map对象mapObject含有一个键值为"key"对应元素值为"value"的Entry项

2、hasItem:

assertThat(iterableObject, hasItem (element));

表明被测的迭代对象iterableObject含有元素element项则测试通过

3、hasKey:

assertThat(mapObject, hasKey (“key”));

断言被测的Map对象mapObject含有键值“key”

4、hasValue:

assertThat(mapObject, hasValue(value));

断言被测的Map对象mapObject含有元素值value

import org.hamcrest.core.AllOf;
import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.bruce.demo.Calculator;

/**
 * 计算器的这个测试类
 */
public class TestHancrestCalture {
  
  //第一步:应该维护Calture的这个对象
  private Calculator calture=null;
  //第二步:初始化对象以及数据
  
  @Before             //类的对象初始化的时候 进行调用 (这个使用的比较多)
  //@BeforeClass        //这个注解是在 类的对象初始化之前 进行调用了  也就是说 对象还没有存在就被调用了
  public void init(){
    calture=new Calculator();
  }
  
   
  @Test
  public void testAdd() throws Exception {
    //下面就进行操作了
    int acResult=calture.add(1,1);
    //这个就稍微复杂点 如果记不住 也没关系  你可以写多条
    assertThat(acResult,AllOf.allOf(IsNull.notNullValue(),IsEqual.equalTo(2)));
  }
  
  
  @After
  public void destory(){
    calture=null;
  }
}      

1.6 Unit4新断言-Hamcrest的常用方法

现在有50个Service 50个DAO

现在我开发好了一个功能:按照刚才的说法要把所有的测试用例都运行一次 至少运行60次显然不靠谱

suite在这种情况下 就因运而生了

suite是用来干嘛的呢?

可以使用Suite这门技术一次性运行多个测试用例

 TestA

public class TestA {
     
  private Calculator calture=null;
  
  @Before
  public void init(){
    calture=new Calculator();
  }
  
  @Test
  public void add(){
    int acResult=calture.add(1,1);
    Assert.assertEquals(2, acResult);
  }
}      

 TestB

public class TestB {
private Calculator calture=null;
  
  @Before
  public void init(){
    calture=new Calculator();
  }
  
  @Test(expected=ArithmeticException.class)
  public void testCf(){
    calture.chu(1,0);
  }
}      

 TestAB

@RunWith(Suite.class)    //这个是告诉这个测试用例使用那个类来进行运行
@SuiteClasses({TestA.class,TestB.class})
public class TestAB {

}      

2.2. Stub(桩)的使用

场景:现在要写Service层的测试用例,但是DAO并没有开发好,但是DAO的整个约束是有的 整个DAO的接口是有的,只是没有实现而已,但是你就是要写测试.

思想:就是自己编写一个接口的实现类,然后这个接口的实现类中访问数据库的时候,使用了Map来模拟整个数据的存储、在每一个调用的方法上直接,使用Map来进行操作的这种测试模式 就叫做stub.

 新建一个Dao层接口

public interface IUserDAO {
    /**
     * 通过id找用户
     * @Title: findUserById   
     * @Description: TODO
     * @param: @param uId
     * @param: @return      
     * @return: User      
     * @throws
     */
    public User findUserById(Serializable uId);
    
}      

 新建一个Sevice接口

public class UserService {
   
  private IUserDAO userDAO=null;
  
  public void setUserDAO(IUserDAO userDAO) {
    this.userDAO = userDAO;
  }
  
  /**
   * 现在要测试这个方法
   * @Title: getUserById   
   * @Description: TODO
   * @param: @param uId
   * @param: @return      
   * @return: User      
   * @throws
   */
  public User getUserById(Serializable uId){
    return userDAO.findUserById(uId);
  }
  
}      

 User实现类

public class User implements Serializable {

  private int uId;
  private String uName;
  private String uPwd;

  public int getuId() {
    return uId;
  }

  public void setuId(int uId) {
    this.uId = uId;
  }

  public String getuName() {
    return uName;
  }

  public void setuName(String uName) {
    this.uName = uName;
  }

  public String getuPwd() {
    return uPwd;
  }

  public void setuPwd(String uPwd) {
    this.uPwd = uPwd;
  }

  public User(int uId, String uName, String uPwd) {
    super();
    this.uId = uId;
    this.uName = uName;
    this.uPwd = uPwd;
  }

  public User() {
    super();
  }

  @Override
  public String toString() {
    return "User [uId=" + uId + ", uName=" + uName + ", uPwd=" + uPwd + "]";
  }
}      
public class UserDAOStub implements IUserDAO {

  // 使用Map集合来模拟数据库
  private Map<Integer, User> maps = new HashMap<Integer, User>();
  
  {
    maps.put(1, new User(1, "zhangsan", "123"));
    maps.put(2, new User(2, "lisi", "110"));
    maps.put(3, new User(3, "wangwu", "119"));
  }

  public User findUserById(Serializable uId) {
    return maps.get(uId);
  }
}      

 测试类

public class TestUserService {

  private UserService userService=null;
  private User exUser=null;
  private UserDAOStub userDAOStub=null;
  
  @Before
  public void init(){
    userService=new UserService();
    exUser=new User(1,"zhangsan","123");
    userDAOStub=new UserDAOStub();
    //在userSerVice中进行设置
    userService.setUserDAO(userDAOStub);
  }
  
  /**
   * 用过id找用户
   * @Title: testGetUserById   
   * @Description: TODO
   * @param: @throws Exception      
   * @return: void      
   * @throws
   */
  @Test
  public void testGetUserById() throws Exception {
     User acUser=userService.getUserById(1);  
     //下面紧接着进行断言
     Assert.assertEquals(exUser.getuId(),acUser.getuId());
     Assert.assertEquals(exUser.getuName(),acUser.getuName());
     Assert.assertEquals(exUser.getuPwd(),acUser.getuPwd());
  }
}      

3.dbunit的使用

专门用来进行DAO层测试的、在分层测试中每一层都要使用不同的框架和技术来进行测试、是因为每一层在测试的时候的着重点不一样

 搭建Dao层环境

<dependencies>

    <!--导入我们的dbunit的包 -->
    <dependency>
      <groupId>org.dbunit</groupId>
      <artifactId>dbunit</artifactId>
      <version>2.5.3</version>
    </dependency>

    <!-- dbutils -->
    <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.6</version>
    </dependency>

    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>

  </dependencies>      

 实体类

public class User implements Serializable {

  private int uId;
  private String uName;
  private String uPwd;

  public int getuId() {
    return uId;
  }

  public void setuId(int uId) {
    this.uId = uId;
  }

  public String getuName() {
    return uName;
  }

  public void setuName(String uName) {
    this.uName = uName;
  }

  public String getuPwd() {
    return uPwd;
  }

  public void setuPwd(String uPwd) {
    this.uPwd = uPwd;
  }

  public User(int uId, String uName, String uPwd) {
    super();
    this.uId = uId;
    this.uName = uName;
    this.uPwd = uPwd;
  }

  public User() {
    super();
  }

  @Override
  public String toString() {
    return "User [uId=" + uId + ", uName=" + uName + ", uPwd=" + uPwd + "]";
  }
}      

 JDBC帮助类

/**
 * 编写JDBC的帮助类
 */
public class JdbcUtils {
   
  private static ComboPooledDataSource dataSource=null;
  
  static{
    dataSource=new ComboPooledDataSource();
    try {
      dataSource.setJdbcUrl("jdbc:mysql:///DbunitTest");
      dataSource.setDriverClass("com.mysql.jdbc.Driver");
      dataSource.setUser("root");
      dataSource.setPassword("root");
    } catch (PropertyVetoException e) {
      e.printStackTrace();
    }
  }
  /**
   * 获取连接
   * @Title: getConnection   
   * @Description: TODO
   * @param: @return
   * @param: @throws SQLException      
   * @return: Connection      
   * @throws
   */
  public static Connection getConnection() throws SQLException{
    return dataSource.getConnection();
  }
  
  
  /**
   * 获取操作数据库的对象
   * @Title: getQueryRunner   
   * @Description: TODO
   * @param: @return      
   * @return: QueryRunner      
   * @throws
   */
  public static QueryRunner getQueryRunner(){
    return new QueryRunner(dataSource);
  }
  
}      

 Dao层

/**
 * 用户的DAO接口
 * @ClassName:  UserDAO   
 */
public class UserDAO {
    /**
     * @throws SQLException 
     * 通过id找用户 
     * @Title: getuserById   
     * @Description: TODO
     * @param: @param uId
     * @param: @return      
     * @return: User      
     * @throws
     */
    public User getuserById(Serializable uId) throws SQLException{
        return JdbcUtils.getQueryRunner().query("select * from t_user where uId=?",new BeanHandler<User>(User.class),uId);
    }
}      

 测试

**
     * 使用dbunit测试的五个步骤
     *    1>:备份表的数据  ( 数据隔离)
     *          1>:备份所有表
     *          2>:备份一张表
     *    2>:清空表里面的数据      
     *    3>:插入测试的数据
     *    4>:进行测试
     *    5>:还原表的数据     
     */
/**
 * dbunit的使用
 *
 */
public class TestUserDAO { 
    
    private DatabaseConnection connection=null;
    
    private UserDAO userDAO=null;
    
    private User exUser=null;
    
    @Before
    public void init() throws DatabaseUnitException, SQLException{
        //这个里面的参数就是实际上连接数据库的这个参数
        connection=new DatabaseConnection(JdbcUtils.getConnection());
        userDAO=new UserDAO();
        exUser=new User(1,"狗剩","123");
    }
    
     /**
      * 测试
      * @Title: testGetUserById   
      * @Description: TODO
      * @param: @throws Exception      
      * @return: void      
      * @throws
      */
    @Test
    public void testGetUserById() throws Exception {
        //backAllTable();  //备份所有表
        //backOneTable(); //备份一张表
        //insertData(); //初始化一张表
        //测试逻辑
        User acUser=userDAO.getuserById(1);
        //接下来进行断言
        Assert.assertEquals(exUser.getuName(), acUser.getuName());
        Assert.assertEquals(exUser.getuId(), acUser.getuId());
        Assert.assertEquals(exUser.getuPwd(), acUser.getuPwd());
        
        //进行数据的还原
        resumeTable();
    }
    /**
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws DataSetException 
     * 数据最终的还原
     * @Title: resumeTable   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
    private void resumeTable() throws Exception {
        IDataSet dataSet=new FlatXmlDataSet(new InputSource(new FileInputStream(new File("G:\\stsWorkSpace\\Dbunit-Demo\\src\\main\\resources\\t_user.xml"))));
        DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
    }


    /**
     * @throws SQLException 
     * @throws DatabaseUnitException 
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws DataSetException 
     * 清空表中的数据 并进行数据的插入
     * @Title: insertData   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
    private void insertData() throws FileNotFoundException, IOException, DatabaseUnitException, SQLException {
         FlatXmlDataSet dataSet=new FlatXmlDataSet(new InputSource(TestUserDAO.class.getClassLoader().getResourceAsStream("initdata.xml")));
         //FlatXmlDataSet dataSet=new FlatXmlDataSet(new InputSource(Thread.currentThread().getClass().getClassLoader().getResourceAsStream("data.xml")));
         DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
    }


    /**
     * @throws AmbiguousTableNameException 
     * 备份一张表的数据
     * @Title: backOneTable   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
    private void backOneTable() throws Exception {
        //初始化一个dataSet对象
        QueryDataSet dataSet=new QueryDataSet(connection);
        //告诉他要备份表的名字
        dataSet.addTable("t_user");
        FlatXmlDataSet.write(dataSet,new FileOutputStream(new File("G:\\stsWorkSpace\\Dbunit-Demo\\src\\main\\resources\\t_user.xml")));
    }


    /**
     * @throws SQLException 
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws DataSetException 
     * 备份所有表的数据
     * @Title: backAllTable   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
    private void backAllTable() throws DataSetException, FileNotFoundException, IOException, SQLException {
        //获取dataSet对象
        IDataSet dataSet=connection.createDataSet();
        //使用属性的形式来完成数据的备份
       // FlatXmlDataSet.write(dataSet,new FileOutputStream(new File("G:\\data.xml")));
        //这个就表示的数使用节点的形式来表示这个数据
        XmlDataSet.write(dataSet,new FileOutputStream(new File("G:\\stsWorkSpace\\Dbunit-Demo\\src\\main\\resources\\data.xml")));
    }
}      

 测试优化

 创建一个工具类

/**
 * dbutils的一个帮助类
 */
public class AbstractDbutilsTestCase {
    
    private DatabaseConnection connection=null;
    
    private File temFile=null;    //备份数据的存储位置
    
    private IDataSet testDataSet=null; //这个就是测试数据的dataSet数据
    
    public AbstractDbutilsTestCase(Connection conn,IDataSet dataSet) throws DatabaseUnitException {
        connection=new DatabaseConnection(conn);
        this.testDataSet=dataSet;
    }
    
    /**
     * @throws Exception 
     * 备份所有的表
     * @Title: resultAllTable   
     * @Description: TODO
     * @param: @param tabNames      
     * @return: void      
     * @throws
     */
    public void backAllTable(String... tabNames) throws Exception {
        QueryDataSet dataSet=new QueryDataSet(connection);
        for (String tabName : tabNames) {
              dataSet.addTable(tabName);
        }
        //这里就可以开始备份了
        temFile=File.createTempFile("backTable",".xml");
        FlatXmlDataSet.write(dataSet,new FileOutputStream(temFile));
    }
    
    /**
     * 备份一张表
     * @Title: backOneTable   
     * @Description: TODO
     * @param: @param tabName
     * @param: @throws Exception      
     * @return: void      
     * @throws
     */
    public void backOneTable(String tabName) throws Exception{
        backAllTable(tabName);  
    }
    
    /**
     * @throws SQLException 
     * @throws DatabaseUnitException 
     * 插入测试数据
     * @Title: insertTestData   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
    public void insertTestData() throws DatabaseUnitException, SQLException{
        //插入测试的数据
        DatabaseOperation.CLEAN_INSERT.execute(connection, testDataSet);
    }
    /**
     * @throws IOException 
     * @throws SQLException 
     * @throws DatabaseUnitException 
     * @throws FileNotFoundException 
     * @throws DataSetException 
     * 恢复表的数据
     * @Title: resumeTable   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
    public void resumeTable() throws DataSetException, FileNotFoundException, DatabaseUnitException, SQLException, IOException{
        DatabaseOperation.CLEAN_INSERT.execute(connection,new FlatXmlDataSet(new InputSource(new FileInputStream(temFile))));
    }
    
}      

 测试

/**
 * 测试的类
 */
public class TestUserDAO1 extends AbstractDbutilsTestCase {

  private UserDAO userDAO = null;

  private User exUser = null;

  @Before
  public void init() throws Exception {
    backOneTable("t_user");
    insertTestData();
    userDAO = new UserDAO();
    exUser = new User(1, "狗剩1", "123");
  }

  public TestUserDAO1() throws Exception {
    super(JdbcUtils.getConnection(), new FlatXmlDataSet(new InputSource(TestUserDAO1.class.getClassLoader().getResourceAsStream("initdata.xml"))));
  }

  @Test
  public void testGetUserById() throws Exception {
    // 测试逻辑
    User acUser = userDAO.getuserById(1);
    // 接下来进行断言
    Assert.assertEquals(exUser.getuName(), acUser.getuName());
    Assert.assertEquals(exUser.getuId(), acUser.getuId());
    Assert.assertEquals(exUser.getuPwd(), acUser.getuPwd());
  }
  
  @After
  public void after() throws DataSetException, FileNotFoundException, DatabaseUnitException, SQLException, IOException{
    resumeTable();
  }
}      

4.EasyMock的使用 -测试业务逻辑层

 EasyMock注重的的是调用的过程(顺序、次数) 不侧重结果

 dbunit注重的是调用的结果

调用的过程;

举例: 测试的是service中 dao调用了几次,调用的顺序是什么?

 创建Dao层接口

public interface UserDAO {

  /**
     * 有返回的情况
     * @Title: getUserById   
     * @Description: TODO
     * @param:       
     * @return: void      
     * @throws
     */
  public User  getUserById();
  /**
   * 没参数返回的
   * @Title: add   
   * @Description: TODO
   * @param:       
   * @return: void      
   * @throws
   */
  public void add();
}      

 业务逻辑层实现类

/**
 * 业务逻辑类
 */
public class UserService {

  private UserDAO userDAO=null;
  public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
  }
  
  
  public User getUserById(){
    return userDAO.getUserById();
  }
  
  public void add(){
      userDAO.add();  
  }
  
  public void aaa(){
    userDAO.add();
    userDAO.getUserById();
  }
}      

 测试依赖

<dependency>
  <groupId>org.easymock</groupId>
  <artifactId>easymock</artifactId>
  <version>3.4</version>
  <scope>test</scope>
</dependency>      

 测试

/**
 * EasyMock的使用
 */
public class TestUserService {
  
  private UserService userService=null;  //申明UserService对象
  
  private User exUser=null;
  
  @Before
  public void init(){
    userService=new UserService();
    exUser=new User(1,"小张","123");
  }
  
  @Test
  public void testGetUserById() throws Exception {
    //第一步:使用EasyMock来生成UserDAO的对象
    UserDAO userDAO=EasyMock.createMock(UserDAO.class);
    
    //第二步:做记录(就是你要调用那个方法 需要返回怎样的值)  记住:有多少方法就要记录多少次
    EasyMock.expect(userDAO.getUserById()).andReturn(exUser);
    
    //第三步:使能上面的记录
    EasyMock.replay(userDAO);
    
    //第四步:业务逻辑和方法的调用
    userService.setUserDAO(userDAO);
    userService.getUserById();
    
    //进行校验
    EasyMock.verify(userDAO);
  }
}      

 测试的是没有返回值的记录模式

@Test
  public void testAdd() throws Exception {
    // 第一步:创建接口的实现类对象
    UserDAO userDAO = EasyMock.createMock(UserDAO.class);
    // 第二步:进行记录
    // 如果没有返回值的话那么闲调用一下这个方法 再进行记录
    // 下面的这个调用并不是真正的进行调用而是进行一个记录而已
    userDAO.add();
    EasyMock.expectLastCall(); // 记录调用的第一次
    userDAO.add();
    EasyMock.expectLastCall(); // 记录调用的第二次
    // 第三步:使能记录
    EasyMock.replay(userDAO);
    // 第四步:设置对象调用
    userService.setUserDAO(userDAO);
    // 进行业务逻辑的调用
    userService.add();
    userService.add();
    // 第五步:验证这个结果的正确性
    EasyMock.verify(userDAO);
  }      

 有返回值和没有返回值的混合使用模式

@Test
  public void testAddAndGet() throws Exception {
    // 第一步:创建接口的实现类对象
    UserDAO userDAO = EasyMock.createMock(UserDAO.class);
    // 第二步:进行记录
    // 如果没有返回值的话那么闲调用一下这个方法 再进行记录
    // 下面的这个调用并不是真正的进行调用而是进行一个记录而已
    // 这个是记录没有返回值的情况

    // 记录调用的时候有返回值的情况
    EasyMock.expect(userDAO.getUserById()).andReturn(exUser);
    userDAO.add();
    EasyMock.expectLastCall(); // 记录调用的第一次

    // 第三步:使能记录
    EasyMock.replay(userDAO);
    // 第四步:设置对象调用
    userService.setUserDAO(userDAO);
    // 进行业务逻辑的调用
    userService.getUserById();
    userService.add();
    // 第五步:验证这个结果的正确性
    EasyMock.verify(userDAO);
  }      

 创建具有严格顺序的Mock

/**
   * 这个是校验具有严格意义上的Mock(调用的时候是按照 你记录的顺序来调用的)
   * @Title: testAddAndGetStrick   
   * @Description: TODO
   * @param: @throws Exception      
   * @return: void      
   * @throws
   */
  @Test
  public void testAddAndGetStrick() throws Exception {
    //这个表示的是创建的是严格意义上的Mock
    UserDAO userDAO=EasyMock.createStrictMock(UserDAO.class);
    
    //第二步:进行记录
    //如果没有返回值的话那么先调用一下这个方法 再进行记录
    //下面的这个调用并不是真正的进行调用而是进行一个记录而已
    //这个是记录没有返回值的情况
    
    //记录调用的时候有返回值的情况
    
    EasyMock.expect(userDAO.getUserById()).andReturn(exUser);
    
    
    userDAO.add();
    EasyMock.expectLastCall();  //记录调用的第一次
    
    //第三步:使能记录
    EasyMock.replay(userDAO);
    //第四步:设置对象调用
    userService.setUserDAO(userDAO);
    //进行业务逻辑的调用
    userService.aaa();
    //第五步:验证这个结果的正确性
    EasyMock.verify(userDAO);
  }      

 具有多个DAO的时候测试的方式

public interface IADAO {
   
  public void aa();
  
  public void bb();
}

public interface IBDAO {
    
  public void cc();
  
  public void dd();
}

public class AService {

  private IADAO iadao = null;

  private IBDAO ibdao = null;

  public void setIbdao(IBDAO ibdao) {
    this.ibdao = ibdao;
  }

  public void setIadao(IADAO iadao) {
    this.iadao = iadao;
  }

  /**
   * 单个
   * 
   * @Title: a
   * @Description: TODO
   * @param:
   * @return: void
   * @throws
   */
  public void a() {
    iadao.aa();
    iadao.bb();
  }

  /**
   * 组合
   * 
   * @Title: b
   * @Description: TODO
   * @param:
   * @return: void
   * @throws
   */
  public void b() {
    iadao.aa();
    iadao.bb();
    ibdao.cc();
    ibdao.dd();
  }

  /**
   * 组合乱序
   * 
   * @Title: c
   * @Description: TODO
   * @param:
   * @return: void
   * @throws
   */
  public void c() {
    iadao.aa();
    ibdao.cc();
    iadao.bb();
    ibdao.dd();
  }
}      

 测试类

/**
 */
public class TestAService {
    
  private AService aService=null;
  
  @Before
  public void init(){
    aService=new AService();
  }
  
  
  /**
   * 测试单个的调用这个方法
   * @Title: testA   
   * @Description: TODO
   * @param: @throws Exception      
   * @return: void      
   * @throws
   */
  @Test
  public void testA() throws Exception {
    //创建对象(一般用在同时测多个业务逻辑的时候)
    IMocksControl control=EasyMock.createControl();
    //创建第一个对象
    IADAO iadao=control.createMock(IADAO.class);
    //创建第二个对象
    IBDAO ibdao=control.createMock(IBDAO.class);
    //做记录
    iadao.aa();
    EasyMock.expectLastCall();
    iadao.bb();
    EasyMock.expectLastCall();
    //使能这个记录
    EasyMock.replay(iadao);
    //设置和调用
    aService.setIadao(iadao);
    aService.a();
    //校验
    EasyMock.verify(iadao);
  }
  
  
  /**
   * 通过controll来创建Mock
   * @Title: testB   
   * @Description: TODO
   * @param: @throws Exception      
   * @return: void      
   * @throws
   */
  @Test
  public void testB() throws Exception {
    //创建对象(一般用在同时测多个业务逻辑的时候)
    IMocksControl control=EasyMock.createStrictControl();
    //创建第一个对象
    IADAO iadao=control.createMock(IADAO.class);
    //创建第二个对象
    IBDAO ibdao=control.createMock(IBDAO.class);
    //做记录
    iadao.aa();
    EasyMock.expectLastCall();
    iadao.bb();
    EasyMock.expectLastCall();
    ibdao.cc();
    EasyMock.expectLastCall();
    ibdao.dd();
    EasyMock.expectLastCall();
    
    control.replay();
    
    //设置和调用
    aService.setIadao(iadao);
    aService.setIbdao(ibdao);
    aService.b();
    //校验
    control.verify();
  }
  
  
  @Test
  public void testC() throws Exception {
    //创建对象(一般用在同时测多个业务逻辑的时候)
    IMocksControl control=EasyMock.createControl();
    //创建第一个对象
    IADAO iadao=control.createMock(IADAO.class);
    //创建第二个对象
    IBDAO ibdao=control.createMock(IBDAO.class);
    //做记录
    iadao.aa();
    EasyMock.expectLastCall();
    iadao.bb();
    EasyMock.expectLastCall();
    ibdao.cc();
    EasyMock.expectLastCall();
    ibdao.dd();
    EasyMock.expectLastCall();
    
    //使用下面来做使能
    control.replay();
    
    //设置和调用
    aService.setIadao(iadao);
    aService.setIbdao(ibdao);
    aService.c();
    //校验(使用这个来进行校验)
    control.verify();
  }
  
  @Test
  public void testC1() throws Exception {
    //创建对象(一般用在同时测多个业务逻辑的时候)
    IMocksControl control=EasyMock.createStrictControl();
    //创建第一个对象
    IADAO iadao=control.createMock(IADAO.class);
    //创建第二个对象
    IBDAO ibdao=control.createMock(IBDAO.class);
    //做记录
    iadao.aa();
    EasyMock.expectLastCall();
    ibdao.cc();
    EasyMock.expectLastCall();
    iadao.bb();
    EasyMock.expectLastCall();
    ibdao.dd();
    EasyMock.expectLastCall();
    
    //使用下面来做使能
    control.replay();
    
    //设置和调用
    aService.setIadao(iadao);
    aService.setIbdao(ibdao);
    aService.c();
    //校验(使用这个来进行校验)
    control.verify();
  }
  
}      

5.SpringTest使用

 导入测试的这个包

<!--导入这个SpringTest的相关包 -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.7.RELEASE</version>
      <scope>test</scope>
    </dependency>      
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
       @RunWith(SpringJUnit4ClassRunner.class)
       public class AbstractSpringTestCase {
                //启动Spring容器
               
                
 }      
public class TestUserService extends AbstractSpringTestCase{
   
    @Autowired
    private UserService userService = null;

   @Test
   public void testA() throws Exception {
           userService.add();
     }
     }
}