告别祈祷式编程|单元测试在项目里的正确落地姿势_程序员

告别祈祷式编程|单元测试在项目里的正确落地姿势_程序员_02

前言

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是认为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。本文将带大家介绍几款主流的单元测试使用方法,希望可以帮到大家。

公众号:「浅羽的IT小屋」

1、为什么要使用单元测试?

「好处:」

  • 可以使用单元测试来完成模块功能的一个测试

  • 使用单元测试可以更好的完成模块的回归测试

「在开发中一般要进行如下测试:」

  • 单元测试:一般情况下就是完成我们模块功能的一个检测

  • 回归测试:当我们开发好一个功能之后,这个功能是否会影响其他已经开发好的这个功能

  • 集成测试:简单的说就是项目开发完成的时候,这个所有功能是否完整,以及功能之间是否存在bug

  • 公测:进行公测

2、Junit的使用

「简介:」

  • Junit是单元测试框架工具,在项目开发中是经常用到的,利用Junit4进行单元测试非常简单方便,所以熟悉Junit是很有必要的

「主要用法:」

  @Before      //初始化数据用的
  @BeforeClass  //初始化数据用的(只是执行一次)
  @After       //对象销毁的时候用的
  @AfterClass   //对象销毁的时候用的(只是执行一次) 
  @Test(expected=xxx.class、timeout=5000) (测试:期望出现某一类异常)

3、Hamcrest的使用(Junit的一个补充)

「使用原因:」

  • 使用过Junit的应该有体验:在实际开发中,一些基本的断言,如equal,null,true它们的可读性并不是很好。而且很多时候我们要比较对象、集合、Map等数据结构。这样我们要进行大段的字段获取再断言。或者干脆自己编写表达式并断言其结果

  • Junit4.4引入了Hamcrest框架,Hamcrest提供了一套匹配符,这些匹配符更接近自然语言,可读性高,更加灵活

  • 需求:假设说加法的上面,加上一个不为null的一个断言,这个时候就出现了两个断言,这时候你就需要写两次,有没有办法只写一次呢?有

  //使用这个Hamcrest来进行断言

//        Assert.assertThat(result, IsNull.notNullValue());

        // AllOf:所有的条件都要成立才表示校验成功
        // AnyOf:一个条件校验成功那么才表示的是校验成功
        // IsEqual:相等
        // IsInstanceOf:这个就表示判定的是对象是否是某一个类的对象
        // IsNot:不是某一个类的对象
        // IsNull:判断空值
        // StringEndWith:以什么结尾
        // StringStartsWith:这个表示的是以什么开始
        // SubStringMatcher:截取的字符串和谁匹配


//        Assert.assertThat(result, AllOf.allOf(IsNull.notNullValue(), IsEqual.equalTo(30)));

//       Assert.assertThat(result, AnyOf.anyOf(IsNull.notNullValue(), IsEqual.equalTo(30)));

「Unit4新断言-Hamcrest的常用方法:」

  • 字符相关匹配符

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

4、Suit的使用

「需求:」

  • 现在有30个实体,每个DAO和每个Service都编写了测试用例。所以至少有60个测试类,当我们开发一个功能的时候,我们需要检测当前开发好的功能是否影响了其他已经开发好的功能,这个时候需要运行这60个测试用例,只有所有的测试用例都没有问题,才确定当前开发的功能对其他功能是没有影响的

  • 这个时候就需要运用Suit,Suit的作用就是可以一次性的运行多个测试用例

@RunWith(Suite.class)   //表示的是使用什么类来运行
@Suite.SuiteClasses({TestCaltureB.class,TestCaltureA.class})  //这个表示的是要运行哪些类
public class TestCaltureAB {
}

5、Stub(装)的使用

「解决的问题:」

  • 假设两个人做开发,一个人做的是DAO,另外一个人做的是Service,现在的问题是DAO层还没有来得及开发,只是有约束规范(只有接口没有实现),现在是Service层需要测试,那怎么办呢?

  • Stub的思想就是:自己编写DAO的实现类使用Map集合来模拟数据库的数据以及访问的这个过程,就叫做Stub

「具体使用:」

  • 首先声明DAO的接口

public interface IUserDAO {
    /**
     * 通过id找用户
     * @param userId
     * @return
     */
    User getUserById(Serializable userId);
}

  • 编写Service的实现类

public class UserService {

    public IUserDAO userDAO=null;

    public void setUserDAO(IUserDAO userDAO) {
        this.userDAO = userDAO;
    }

    /**
     * 通过id找用户
     * @param userId
     * @return
     */
    public User getUserById(Serializable userId){

        User user=userDAO.getUserById(userId);

        return user;
    }

}

  • 编写Stub的DAO的实现类

public class UserDAOStub implements IUserDAO{

    //使用map集合来模拟我们的数据库
    private Map<Integer,User> users=new HashMap<>();

    public UserDAOStub() {
        for (int i=0;i< 10;i++){
            users.put(i+1,new User(i+1,i+1+"",i+1+""));
        }
    }

    @Override
    public User getUserById(Serializable userId) {
        return users.get(userId);
    }
}

  • 编写测试的类

public class TestUserService {

    private UserService userService=null;
    private User exUser=null;

    @Before
    public void init(){
        userService=new UserService();
        exUser=new User();
        //期望返回的的这个用户对象
        exUser.setPassword("1");
        exUser.setUserId(1);
        exUser.setUserName("1");

        UserDAOStub userDAOStub = new UserDAOStub();
        userService.setUserDAO(userDAOStub);

    }
    @Test
    public void testGetUserById(){
        User user=userService.getUserById(1);
        //接下来就进行断言了
        Assert.assertEquals(exUser.getUserId(),user.getUserId());
        Assert.assertEquals(exUser.getPassword(),user.getPassword());
        Assert.assertEquals(exUser.getUserName(),user.getUserName());
    }

    @After
    public void close(){
        userService=null;
    }
}

6、dbunit的使用

「主要用途:」

  • dbunit是专门用来测试DAO层的,以后开发中DAO的测试就可以使用dbunit来进行

「使用流程:」

  • 备份所有的表

 private void backAllTable() throws SQLException, IOException, DataSetException {

        //第一步:获取连接上的dataSet对象
        IDataSet dataSet = conn.createDataSet();
        //第二步:将数据进行备份
        //使用属性来描述要备份的这个数据
//      FlatXmlDataSet.write(dataSet,new FileOutputStream(new File("G:/allTable.xml")));

        //使用节点来描述要备份的这个数据
        XmlDataSet.write(dataSet, new FileOutputStream(new File("G:/allTable1.xml")));
    }

  • 备份一张表

 
/**
 * 备份一张表的数据
 */
private void backOneTable() throws DataSetException, IOException {
    //创建一个查询的DataSet对象
    QueryDataSet dataSet = new QueryDataSet(conn);
    //第二步:添加要备份的表名
    dataSet.addTable("t_user");
    //第三步:进行备份
    FlatXmlDataSet.write(dataSet, new FileOutputStream(new File("G:/allTable.xml")));
}

  • 插入测试数据

/**
 * 插入准备好的数据到数据库
 */
private void insertDataTable() throws DatabaseUnitException, SQLException {
    //获取插入数据的DataSet对象
    IDataSet dataSet = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(TestUserDAO.class.getClassLoader().getResourceAsStream("table.xml"))));
    DatabaseOperation.CLEAN_INSERT.execute(conn, dataSet);
}

  • 测试

@Test
public void testFindUserById() throws SQLException, IOException, DatabaseUnitException {
     backOneTable();
     insertDataTable();
    // 编写测试代码的地方
    User acUser=userDAO.findUserById(78);  //实际返回的用户对象
    //下一步:进行断言
    Assert.assertEquals(exUser.getUserId(),acUser.getUserId());
    Assert.assertEquals(exUser.getUserName(),acUser.getUserName());
    Assert.assertEquals(exUser.getPassword(),acUser.getPassword());

    //还原数据库的数据
    resumeTable();
}

  • 还原这个数据

/**
 * 还原数据库的数据
 */
private void resumeTable() throws IOException, DatabaseUnitException, SQLException {
    //备份数据的DataSet对象
    IDataSet dataSet=new FlatXmlDataSet(new InputSource(new FileInputStream(new File("G:/allTable.xml"))));

    DatabaseOperation.CLEAN_INSERT.execute(conn,dataSet);
}

  • 整体代码如下:

package com.qy.dbunit;

import com.qy.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.AmbiguousTableNameException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.dataset.xml.XmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.InputSource;

import java.io.*;
import java.sql.SQLException;

/**
 * @Auther: qianyu
 * @Date: 2020/11/17 10:02
 * @Description:
 */
public class TestUserDAO {

    //维护的是用户的DAO的对象
    private UserDAO userDAO=null;

    //实例化dbunit中的这个数据库的连接
    private DatabaseConnection conn = null;

    //期望返回的用户对象值
    private User exUser=null;

    @Before
    public void init() throws Exception {
        conn = new DatabaseConnection(JdbcUtils.getConnection());
        exUser=new User();
        exUser.setUserId(78);
        exUser.setUserName("78");
        exUser.setPassword("78");
        userDAO=new UserDAO();
    }


    /**
     * 第一步:对数据库的数据进行备份
     * 备份一张表的数据
     * 备份整个数据库中的数据
     * 第二步:插入提前准备好的测试数据
     * 第三步:测试
     * 第四步:将数据库的数据清空
     * 第五步:还原数据库的数据
     */

    @Test
    public void testFindUserById() throws SQLException, IOException, DatabaseUnitException {
         backOneTable();
         insertDataTable();
        // 编写测试代码的地方
        User acUser=userDAO.findUserById(78);  //实际返回的用户对象
        //下一步:进行断言
        Assert.assertEquals(exUser.getUserId(),acUser.getUserId());
        Assert.assertEquals(exUser.getUserName(),acUser.getUserName());
        Assert.assertEquals(exUser.getPassword(),acUser.getPassword());

        //还原数据库的数据
        resumeTable();
    }

    /**
     * 还原数据库的数据
     */
    private void resumeTable() throws IOException, DatabaseUnitException, SQLException {
        //备份数据的DataSet对象
        IDataSet dataSet=new FlatXmlDataSet(new InputSource(new FileInputStream(new File("G:/allTable.xml"))));

        DatabaseOperation.CLEAN_INSERT.execute(conn,dataSet);
    }

    /**
     * 插入准备好的数据到数据库
     */
    private void insertDataTable() throws DatabaseUnitException, SQLException {
        //获取插入数据的DataSet对象
        IDataSet dataSet = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(TestUserDAO.class.getClassLoader().getResourceAsStream("table.xml"))));
        DatabaseOperation.CLEAN_INSERT.execute(conn, dataSet);
    }

    /**
     * 备份数据库中所有表中的数据
     */
    private void backAllTable() throws SQLException, IOException, DataSetException {

        //第一步:获取连接上的dataSet对象
        IDataSet dataSet = conn.createDataSet();
        //第二步:将数据进行备份
        //使用属性来描述要备份的这个数据
//      FlatXmlDataSet.write(dataSet,new FileOutputStream(new File("G:/allTable.xml")));

        //使用节点来描述要备份的这个数据
        XmlDataSet.write(dataSet, new FileOutputStream(new File("G:/allTable1.xml")));
    }

    /**
     * 备份一张表的数据
     */
    private void backOneTable() throws DataSetException, IOException {
        //创建一个查询的DataSet对象
        QueryDataSet dataSet = new QueryDataSet(conn);
        //第二步:添加要备份的表名
        dataSet.addTable("t_user");
        //第三步:进行备份
        FlatXmlDataSet.write(dataSet, new FileOutputStream(new File("G:/allTable.xml")));
    }


}

  • 编写测试的基类

package com.qy.base;

import org.apache.commons.dbutils.QueryRunner;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.AmbiguousTableNameException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.xml.sax.InputSource;

import java.io.*;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Auther: qianyu
 * @Date: 2020/11/17 10:58
 * @Description:
 */
public class AbstractDbunitTestCase implements Serializable{

    //dbunit的这个连接
    private DatabaseConnection conn=null;

    //传入测试数据的dataSet对象
    private IDataSet dataSetTest=null;

    //创建一个临时文件
    private File temFile=null;

    public AbstractDbunitTestCase(Connection connection,IDataSet dataSetTest) throws DatabaseUnitException {
        conn=new DatabaseConnection(connection);
        this.dataSetTest=dataSetTest;
    }

    /**
     * 备份多张表的数据
     * @param tabNames
     */
    public void backManyTable(String ... tabNames) throws DataSetException, IOException {

        QueryDataSet queryDataSet=new QueryDataSet(conn);
        for (int i=0;i<tabNames.length;i++){
            queryDataSet.addTable(tabNames[i]);
        }

        temFile=File.createTempFile("table",".xml");
        //进行备份
        FlatXmlDataSet.write(queryDataSet,new FileOutputStream(temFile));
    }

    /**
     * 备份一张表
     * @param tableName
     */
    public void backOneTable(String tableName) throws IOException, DataSetException {
       backManyTable(tableName);
    }

    /**
     * 插入测试数据
     */
    public void insertTestData() throws DatabaseUnitException, SQLException {
        DatabaseOperation.CLEAN_INSERT.execute(conn,dataSetTest);
    }

    /**
     * 还原这个表的数据
     */
    public void resumeTable() throws IOException, DatabaseUnitException, SQLException {
        IDataSet dataSet=new FlatXmlDataSet(new InputSource(new FileInputStream(temFile)));
        DatabaseOperation.CLEAN_INSERT.execute(conn,dataSet);
    }
}

  • 使用基类来完成测试

package com.qy.dbunit;

import com.qy.base.AbstractDbunitTestCase;
import com.qy.utils.JdbcUtils;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.InputSource;

import java.sql.SQLException;

/**
 * @Auther: qianyu
 * @Date: 2020/11/17 11:12
 * @Description:
 */
public class TestUserDAO1 extends AbstractDbunitTestCase {

    private UserDAO userDAO=null;

    //期望返回的用户对象值
    private User exUser=null;

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

    @Before
    public void init() throws Exception {
        exUser=new User();
        exUser.setUserId(78);
        exUser.setUserName("78");
        exUser.setPassword("79");
        userDAO=new UserDAO();
        backOneTable("t_user");
        insertTestData();
    }


    @Test
    public void testFindUserById() throws SQLException {
        // 编写测试代码的地方
        User acUser=userDAO.findUserById(78);  //实际返回的用户对象
        //下一步:进行断言
        Assert.assertEquals(exUser.getUserId(),acUser.getUserId());
        Assert.assertEquals(exUser.getUserName(),acUser.getUserName());
        Assert.assertEquals(exUser.getPassword(),acUser.getPassword());
    }
    @After
    public void destory() throws Exception {
       resumeTable();
    }
}

7、EasyMock的使用

「使用场景:」

dbunit是专门用来测试DAO层的
EasyMock是专门用来测试Service层的
DAO层的测试的重点:数据的准确性
Service层测试的重点是DAO的调用次数、DAO层的调用的顺序
EasyMocK的适用场景:就是当Service开发好之后 DAO层还没有来得及开发的时候 Service层需要测试

  • 第一个案例

public class TestUserService {

    private UserService userService=null;

    private User exUser=null;

    @Before
    public void init(){
        userService=new UserService();
        exUser=new User();
        exUser.setUserId(1);
        exUser.setUserName("浅羽");
        exUser.setPassword("123");
    }

    /**
     * 有返回值的情况
     */
    @Test
    public void testFindUserById(){
        //第一步:使用EasyMock生成接口的实现类
        IUserDAO userDAO=EasyMock.createMock(IUserDAO.class);
        //第二步:进行记录
        //下面表示的意思是调用了上面对象的哪一个方法传递,某一个值的时候 希望的返回值是什么?
        EasyMock.expect(userDAO.findUserById(1)).andReturn(exUser);
        EasyMock.expect(userDAO.findUserById(1)).andReturn(exUser);
        //第三步:进行replay(使能:使上面的设置生效)
        EasyMock.replay(userDAO);
        //第四步:进行设置
        userService.setUserDAO(userDAO);
        //第五步:进行测试
        userService.findUserById(1);
        //第六步:进行校验
        EasyMock.verify(userDAO);
    }

    /**
     * 没有返回值的情况
     */
    @Test
    public void testSave(){
        IUserDAO userDAO=EasyMock.createMock(IUserDAO.class);
        //没有返回值的情况
        //第一步:调用(记录中的调用)
        userDAO.save();
        //第二步:告诉他没有返回值
        EasyMock.expectLastCall();
        //第一步:调用(记录中的调用)

        userDAO.save();
        //第二步:告诉他没有返回值
        EasyMock.expectLastCall();

        //第一步:调用(记录中的调用)
        userDAO.save();
        //第二步:告诉他没有返回值
        EasyMock.expectLastCall();


        //使能
        EasyMock.replay(userDAO);
        //设置
        userService.setUserDAO(userDAO);
        //调用
        userService.save();
        //校验
        EasyMock.verify(userDAO);
    }

    /**
     * 测试有参数和没有参数混用的情况
     * 注意:即时改变了顺序 只要你记录了都不会报错(非严格意义上的Mock)
     *
     */
    @Test
    public void testDelete(){

        IUserDAO userDAO=EasyMock.createMock(IUserDAO.class);
        //进行记录
        //记录第一个调用
        EasyMock.expect(userDAO.findUserById(1)).andReturn(exUser);

        //记录第二个调用
        userDAO.delete();
        EasyMock.expectLastCall();

        //第三个:使能
        EasyMock.replay(userDAO);
        //设置
        userService.setUserDAO(userDAO);
        //调用
        userService.delete(1);

        //校验
        EasyMock.verify(userDAO);
    }

    /**
     * 这个玩的是有严格顺序的Mock
     * 严格意义上的Mock对调用的顺序都有联系
     */
    @Test
    public void testDelete1(){
        IUserDAO userDAO=EasyMock.createStrictMock(IUserDAO.class);
        //进行记录
        //记录第一个调用
        EasyMock.expect(userDAO.findUserById(1)).andReturn(exUser);

        //记录第二个调用
        userDAO.delete();
        EasyMock.expectLastCall();

        //第三个:使能
        EasyMock.replay(userDAO);
        //设置
        userService.setUserDAO(userDAO);
        //调用
        userService.delete(1);

        //校验
        EasyMock.verify(userDAO);
    }
}

  • 关于这个的高级应用

public class TestABService {

    private ABService abService=null;

    @Before
    public void init(){
        abService=new ABService();
    }

    /**
     * 测试顺序的问题
     */
    @Test
    public void testMM(){
        //创建实现类
        A a=EasyMock.createStrictMock(A.class);
        B b=EasyMock.createStrictMock(B.class);
        //进行记录
        a.a();
        EasyMock.expectLastCall();

        a.b();
        EasyMock.expectLastCall();

        b.c();
        EasyMock.expectLastCall();

        b.d();
        EasyMock.expectLastCall();

        //使能
        EasyMock.replay(a,b);

        //设置
        abService.setA(a);
        abService.setB(b);

        //调用
        abService.mm();

        //进行认证

        EasyMock.verify(a,b);

    }


    @Test
    public void testMMM(){

        IMocksControl strictControl = EasyMock.createStrictControl();

        A a=strictControl.createMock(A.class);
        B b=strictControl.createMock(B.class);

        //进行记录
        a.a();
        EasyMock.expectLastCall();

        a.b();
        EasyMock.expectLastCall();

        b.c();
        EasyMock.expectLastCall();

        b.d();
        EasyMock.expectLastCall();

        //使能
        strictControl.replay();

        //设置
        abService.setA(a);
        abService.setB(b);

        //调用
        abService.mm();

        //进行认证
        strictControl.verify();
    }
    @Test
    public void testMM1(){

        IMocksControl strictControl = EasyMock.createStrictControl();

        A a=strictControl.createMock(A.class);
        B b=strictControl.createMock(B.class);

        //进行记录
        a.a();
        EasyMock.expectLastCall();

        a.b();
        EasyMock.expectLastCall();

        b.c();
        EasyMock.expectLastCall();

        b.d();
        EasyMock.expectLastCall();

        //使能
        strictControl.replay();

        //设置
        abService.setA(a);
        abService.setB(b);

        //调用
        abService.mm();

        //进行认证
        strictControl.verify();
    }
}

8、SpringTest的使用

「简介:」

  • 整合了Junit4框架,来做单元测试

「具体使用:」

  • 编写基类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:bean-base.xml"})
public class AbstractSpringTestCase {

}

  • 测试

public class TestUserDAO extends AbstractSpringTestCase {

    @Autowired
   private UserDAO userDAO;
    private User exUser=null;

    @Before
    public void init(){
       exUser=new User(1,"浅羽","123");
    }


    @Test
    public void testFindUserById(){
         User acUser= userDAO.findUserById(1);
         //断言
        //下一步:进行断言
        Assert.assertEquals(exUser.getUserId(),acUser.getUserId());
        Assert.assertEquals(exUser.getUserName(),acUser.getUserName());
        Assert.assertEquals(exUser.getPassword(),acUser.getPassword());
    }
}

结语

本篇关于单元测试的主流框架以及工具的介绍就先到这里结束了,后续会出更多关于单元测试系列文章,谢谢大家支持!

告别祈祷式编程|单元测试在项目里的正确落地姿势_单元测试_03

如果你觉得浅羽的文章对你有帮助的话,请在微信搜索并关注「 浅羽的IT小屋 」微信公众号,我会在这里分享一下计算机信息知识、理论技术、工具资源、软件介绍、后端开发、面试、工作感想以及一些生活随想等一系列文章。所见所领,皆是生活。慢慢来,努力一点,你我共同成长...

往期推荐

 

组件必知必会|那些年我们使用过的轮子—Filter和Proxy

【简历加分】hexo框架搭建个人博客站点,手把手教学。

ES开发指南|如何快速上手ElasticSearch

玩转Redis|学会这10点让你分分钟拿下Redis,满足你的一切疑问

吐血推荐|2万字总结Mac所有应用程序、软件工具和相关资料

超级详细|Linux系统下从0到1的玩法大全

IntelliJ IDEA热部署工具JRebel的使用教程

干货!MySQL优化原理分析及优化方案总结

告别祈祷式编程|单元测试在项目里的正确落地姿势_单元测试_04

点点点,一键三连都在这儿!