单元测试的问题
1、为什么要写单元测试
1、为了进行模块功能的测试
黑盒子测试:不管这个方法的实现是怎么回事的 只需要管 这个方法整体测试出来是否满足我们的 要求
白盒子测试:简单的说 我们在测试这个方法的时候 不光要测试整体的功能是否满足要求 还要对当前方法里面所有的测试分支编写我们的测试用例
单元测试 :一般情况下黑盒子测试
2、可以进行回归测试
当我们编写好一个方法的时候 这个方法是否影响了 其他已经编写好的方法呢? 那么这个时候 只需要运行一下 所有的测试用例 如果所有的测试用例 都没有报错 那么就说明你编写的方法没有影响其他方法
2、Junit的使用
public class TestCalture {
private Calture calture;
//初始化这个实例
@Before //这个注解的作用就是在测试用例执行之前进行对象实例化的
// 由 @before修饰的方法 一般情况下用来进行测试的对象以及数据的初始化
public void init(){
calture=new Calture();
}
/**
* 测试加法
*/
@Test
public void testAdd(){
int addResult = calture.add(1, 1);
//执行了结果之后 :判断这个结果和预期结果是否一致
//判断结果正确与否 那么 叫断言
assertEquals(2,addResult);
}
/**
* 测试这个处罚是否正确
* expected:希望返回某一类的异常
* timeout:测试用例执行的超时时间
*/
@Test(expected = ArithmeticException.class,timeout = 5000)
public void testCf(){
int cfResult = calture.cf(10, 0);
assertNotNull(cfResult);
assertEquals(5,cfResult);
}
@After
public void destroy(){
calture=null;
}
}
3、Hamcreast的使用
需求:执行了这个cf方法执行 我需要进行多个判断
这读个判断 只需要一个满足条件就成立了…
这个hamcreat简单的说就是对原来的Junit的功能的增强
比如:同时成立
一个成立就成立呀
判断null呀 等等 都有封装
@Test(/*expected = ArithmeticException.class,timeout = 5000*/)
public void testCf(){
int cfResult = calture.cf(10, 1);
//下面的两个判断 只要其中一个成立了 那么 这个断言就成立了
// 我在断言的时候 不能单独写成一个一个断言 我需要 写到一起怎么办呢?
/*assertNotNull(cfResult);
assertEquals(5,cfResult);*/
assertThat(cfResult, AnyOf.anyOf(IsNull.notNullValue(), IsEqual.equalTo(5)));
/**
* AnyOf.anyOf:一个成立那么就成立
*
* AllOf.allOf():所有成立才成立
*
* IsNull.notNullValue():不能是null值
*
* IsNull.nullValue():必须是null值
*
* IsInstanceOf.instanceOf():必须是某一个类的实例
*
* IsAnything:这个表示的是对象其中一个
*
* IsNot:不能是某一个数据 或者某一个对象
*/
}
4、Suite的使用
场景:我要一起运行多个测试用例
当我们开发好一个功能之后 如果需要手动的去云星宇一个一个测试用例 那么 就太浪费时间了 那么怎么办呢?
在这种场景下 suite就应运而生了…
4.1、准备第一个测试用例
public class TestCaltuteA {
private Calture calture=null;
@Before
public void init(){
calture=new Calture();
}
@Test
public void testAdd(){
int addResult = calture.add(1, 1);
Assert.assertEquals(2,addResult);
}
}
4.2、准备第二个测试用例
public class TestCaltuteB {
private Calture calture=null;
@Before
public void init(){
calture=new Calture();
}
@Test
public void testCf(){
int addResult = calture.cf(10, 2);
Assert.assertEquals(5,addResult);
}
}
4.3、准备测试
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestCaltuteA.class,TestCaltuteB.class})
public class TestCaltureAB {
}
5、stub的使用
stub:装逼的装
有这样一种场景:我们分层做开发 A做的是业务逻辑层 B做的是DAO层 那么这个时候 当B刚写玩约束规范(DAO接口) 就请假了 结果A把业务逻辑层写完了 要写测试用例了 咋办呢? 那么这个时候A就想到了一种解决这个问题的方式:stub这种思想
适用场景:DAO有规范但是没有实现的情况下 Service要做测试
5.1、准备DAO接口
public interface IUserDAO {
/**
* 通过id找到用户
* @param id
* @return
*/
User findUserById(int id);
}
5.2、准备业务逻辑层的调用
public class UserService {
private IUserDAO userDAO;
public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
/**
* 测试的方法
* @return
*/
public User findUserById(int id){
//中间经历了无数个步骤
//....
//....
return userDAO.findUserById(id);
}
}
5.3、准备测试类
public class TestUserService {
private UserService userService;
private User exUser;
@Before
public void init(){
userService=new UserService();
userService.setUserDAO(new UserDAOStub());
exUser=new User(1,"小波波:1","密码:1");
}
/**
* 测试通过id找用户的这个方法
*/
@Test
public void testFindUserById(){
User useResult = userService.findUserById(1);
//接下来进行断言
Assert.assertEquals(exUser.getId(),useResult.getId());
Assert.assertEquals(exUser.getUserName(),useResult.getUserName());
Assert.assertEquals(exUser.getPassword(),useResult.getPassword());
}
}
5.4、准备stub的DAO实现
public class UserDAOStub implements IUserDAO {
private Map<Integer,User> userMap=new HashMap<>();
public UserDAOStub(){
for (int i = 1; i <10 ; i++) {
userMap.put(i,new User(i,"小波波:"+i,"密码:"+i));
}
}
@Override
public User findUserById(int id) {
return userMap.get(id);
}
}
6、dbunit的使用
dbunit是用来干嘛的呢? 简单的说 dbunit的主要的功能就是用来做DAO层的测试
不是 dbutils(DAO层的解决方案) 、dbunit(专门用来测试DAO层的框架)
6.1、导包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--DAO层测试的这个框架包-->
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
6.2、编写DAO代码
public class UserDAO {
/**
* 通过id找用户
* @param id
* @return
*/
public User findUserById(int id) throws SQLException {
User user = queryRunner().query("select * from t_user where id=?", new BeanHandler<User>(User.class), id);
return user;
}
}
6.3、编写数据库访问的帮助类
public class JdbcUtils {
private static DruidDataSource dataSource=null;
static{
dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///cd200101");
dataSource.setUsername("root");
dataSource.setPassword("root");
}
/**
* 这个是获取咋们的操作数据库的对象
* @return
*/
public static QueryRunner queryRunner(){
return new QueryRunner(dataSource);
}
/**
* 获取咋们的连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
6.4、编写咋们的基类
public class AbstractDbunitTestCase {
private DatabaseConnection connection;
private File tempFile;
private IDataSet testDataSet; //测试数据的DataSet对象
public AbstractDbunitTestCase(Connection conn,String testFileName) throws DatabaseUnitException {
this.connection=new DatabaseConnection(conn);
InputStream inputStream =AbstractDbunitTestCase.class.getClassLoader().getResourceAsStream(testFileName);
testDataSet=new FlatXmlDataSet(new FlatXmlProducer(new InputSource(inputStream)))