站内搜索: 请输入搜索关键词

当前页面: 开发资料首页Eclipse 专题JUnit in java 真正的测试用例实战

JUnit in java 真正的测试用例实战

摘要: 当今软件测试十分盛行时,本人通过项目实践和个人亲身体会浅谈单元测试
当今软件测试十分盛行时,本人通过项目实践和个人亲身体会浅谈单元测试,本人一直坚持用代码说话的原则,同时也希望个人能给出宝贵意见,共同探讨、共同进步,为中国软件事业有更大的发展共同奋斗!
最早我们项目组开发的项目时,写代码都是从底层一直写到表现层到jsp,然后开发人员在web层调试页面,近乎98%都会报一大堆exception,然后再在代码中加断点一步一步查到底哪一层代码出现问题……,比较好点做法就是在各个类中加上main方法测试,但总体很不理想,给web层开发人员的调试和质量控制人员带来繁重的工作压力;使用单元测试后,针对每一个方法都做严格的把关,大大减少调试的时间;同时质量控制人员返回过来的bug少了近60%,现在对于开发人员写测试用例非常熟练,并且本人根据实际情况对测试用例做了点小小改动(这部分主要在后面代码中详述),带来很好的效果!
单元测试到底给实际开发带来什么好处那?
1           (1)首先对于开发人员来说大大减少调试工作的时间,同时也规范了对于代码安全管理(我们知道那些方法是可以调用的);
2           (2) 对于整个项目来说,有了完整的测试,保证项目最后交付测试有了可靠依据;
3           (3)对于测试人员大大减少bug的反馈;
4           (4)对于项目经理整个项目达到很好的可控;
5          (5)最主要的完整的单元测试给后期维护人员带来很大的便捷!
单元测试好处可能还有很多,但本人只能理解和感悟这么多,希望观者补充!
单元测试配置:
       我将使用eclipsemyEclopse给大家介绍关于JUNIT的环境的简单配置;右键点击项目选择属性,在弹出窗口中到环境变量中添加junit.jar包,这样下一步我们就可以进行单元测试了;
使用eclipse快速开发test Case
如下图:右键选择你要测试的类,在新建中点击“JUnit 测试用例
弹出对话框,配置测试名称和根目录,添加注释等,再点击下一步到下图:
      选择你要测试类中的方法,点击完成!便生成测试类的基本框架,如下代码,我们以对一个DAO类测试为例:
/**//*
 * Copyright reserved 2005 by XXXXCo. Ltd.
 * Author
Fu wei    Date2006-9-4
 */



import junit.framework.TestCase;

/** *//**
 * 
@author Fu wei
 */

public class OrgTypeDAOTest extends TestCase ...{
    
/** *//**
     * 
@param arg0
     */

    
public OrgTypeDAOTest(String arg0) ...{
        
super(arg0);
    }

    
/**//* 
     * @see junit.framework.TestCase#setUp()
     */

    
protected void setUp() throws Exception ...{
        
super.setUp();
    }

    
/**//* 
     * @see junit.framework.TestCase#tearDown()
     */

    
protected void tearDown() throws Exception ...{
        
super.tearDown();
    }
    
/** *//**
     *  
主函数
     * 
@param args
     */

    
public static void main(String[] args)...{
        TestRunner.run(OrgTypeDAOTest .
class);
    }
    
/** *//**
     * {
@link OrgTypeDAO#getOrgTypeList()} 的测试方法。
     */

    
public final void testGetOrgTypeList() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#insertOrgTypeInfo(com.zhjy.mltx.vo.OrgTypeVO)} 的测试方法。
     */

    
public final void testInsertOrgTypeInfo() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#deleteOrgTypeInfo(java.lang.String)} 的测试方法。
     */

    
public final void testDeleteOrgTypeInfo() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#updateOrgTypeInfo(com.zhjy.mltx.vo.OrgTypeVO)} 的测试方法。
     */

    
public final void testUpdateOrgTypeInfo() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#getOrgTypeInfoById(java.lang.String)} 的测试方法。
     */

    
public final void testGetOrgTypeInfoById() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#isRepeatOrgTypeInfo(java.lang.String)} 的测试方法。
     */

    
public final void testIsRepeatOrgTypeInfoString() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#isRepeatOrgTypeInfo(com.zhjy.mltx.vo.OrgTypeVO)} 的测试方法。
     */

    
public final void testIsRepeatOrgTypeInfoOrgTypeVO() ...{
        fail("
尚未实现"); // TODO
    }

    
/** *//**
     * {
@link OrgTypeDAO#getFlatOrgIdByName(java.lang.String)} 的测试方法。
     */

    
public final void testGetFlatOrgIdByName() ...{
        fail("
尚未实现"); // TODO
    }
}
 
 JUnit单元测试一共要注意一下几点:
1import junit.framework.TestCase junit.textui.TestRunner
2)继承junit.framework.TestCase
3)自行添加一个main方法    中调用TestRunner.run(测试类名.class);
4)有一个调用super(String)的构造函数;
        以上都是JUnit必有的特征,除以上外,我们发现有许多以test开头的方法,而这些方法正是我们要测试的方法,Junti测试其实采用的是断言的方式,只要我们在所有test开头中的方法对数据添加断言方法,同时提供很多断言的方法,

<table style="WIDTH: 505.7pt" cellspacing="1" cellpadding="0" width="674" border="1"> <tr> <td style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0.75pt; BORDER-TOP: medium none; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; BORDER-LEFT: medium none; PADDING-TOP: 0.75pt; BORDER-BOTTOM: medium none" colspan="2">

常用断言方法
</td> </tr> <tr> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
assertEquals("失败提示信息","期望数据","测试数据")
</td> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
断言获取数据是否与所期望的相等
</td> </tr> <tr> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
assertNotNull("失败提示信息","测试数据")
</td> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
断言获取数据不为null,否则提示错误
</td> </tr> <tr> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
assertNull("失败提示信息","测试数据")
</td> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
断言获取数据是为null,否则提示错误
</td> </tr> <tr> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
assertTrue("失败提示信息",测试数据blooean)
</td> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
断言获取数据是否为ture,否则提示错误
</td> </tr> <tr> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
fail("失败提示信息");
</td> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
此方法一般放到异常处,遇到此方法,测试将停止!
</td> </tr> <tr> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
assertSame("失败提示信息","期望数据","测试数据")
</td> <td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; PADDING-TOP: 0.75pt">
断言获取数据是否与所期望的相同
</td> </tr> </table>

当我们写完所有方法策略后,JUnit测试如下图:
在方法页面中点击右键在调试方式运行方式中点击JUnit 测试,就运行测试类!
在执行测试类时,执行的大概过程
1)先执行构造方法public OrgTypeDAOTest(String arg0)
2)再执行初始化数据方法protected void setUp()
3)再执行以test开头的测试方法;
4)最后执行protected void tearDown()方法清理对象;
如果测试失败或者错误,将会显示一个红色的亮条;如果测试通过将显示绿色亮条;如下图
 
这样就把一个整个单元测试操作例子演示完成!
可能对于一个测试类中有多个方法要测试,对于后面看着的确有些困难,因此,我对上测试类进行简单的调整,如下代码:
 




import junit.framework.TestCase;
import junit.textui.TestRunner;
import com.zhjy.mock.SpringMock;

/** *//**
 * 
举例测试类
 */

public class OrgTypeDAOTest extends TestCase ...{    //(1)继承TestCase 

    //private OrgTypeDAO orgTypeDAO;
    //private OrgTypeVO orgTypeVO;
    //private String id ;
    /** *//**
     *  
构造方法
     * 
@param arg0 
     */

    
public OrgTypeDAOTest(String arg0) ...{
        
super(arg0);
    }    
    
/**//* 初时化方法
     * @see junit.framework.TestCase#setUp()
     */

    
protected void setUp() throws Exception ...{
        
super.setUp();
        
//测试初始话数据调用类 orgTypeDAO 封装数据的对象orgTypeVO
    }

    
/**//* 执行完清理方法
     * @see junit.framework.TestCase#tearDown()
     */

    
protected void tearDown() throws Exception ...{
        
//清空 对象  ;==null
        //orgTypeDAO =null;
        //orgTypeVO =null;
        super.tearDown();
    }
    
/** *//**
     *  
主函数
     * 
@param args
     */

    
public static void main(String[] args)...{

        TestRunner.run(OrgTypeDAOTest.
class);
    }
    
/** *//**
     * 
测试方法
     * Test method testOrgTypeInfo
     */

    
public void testOrgTypeInfo() ...{
        
//添加
        String id = insertOrgTypeInfo();
        
//列表
        orgTypeList();
        
//修改
        updateOrgTypeInfo(id);
        
//查询
        selectOrgTypeInfoById(id);
        
//校验
        iExistOrgByOrgTypeId(id);
        
//测试是否重复数据方法(add)
        isRepeatOrgTypeInfo(orgTypeVO.getName(),"");
        
//获取数据方法(根据名称)
        selectOrgTypeIdByName(orgTypeVO.getName());
        
//删除
        deleteOrgTypeInfo(id);
    }
    
/**//*
     *
添加初始数据
     */

    
private void setOrgTypeVOAddInfo() ...{
        orgTypeVO.setName("add
中海测试");
        orgTypeVO.setDescription("add
中海测试");
        orgTypeVO.setStatus("1");
    }
    
/**//*
     *
添加初始数据
     */

    
private void setOrgTypeVOUpdateInfo() ...{
        
        
//orgTypeVO.setId(id);
        orgTypeVO.setName("add中海测试");
        orgTypeVO.setDescription("update
中海测试");
        orgTypeVO.setStatus("1");
    }
    
/**//*
     * 
新增方法
     * Test method for {@link OrgTypeDAO#insertOrgTypeInfo(com.zhjy.mltx.vo.OrgTypeVO)}.
     */

    
public String insertOrgTypeInfo() ...{
        setOrgTypeVOAddInfo();
        String id = 
null;
        
try...{
            id = orgTypeDAO.insertOrgTypeInfo(orgTypeVO);
        }
catch(Exception e)...{
            fail("
添加通用组织机构失败!");
        }
        
return id;
    }
    
/**//*
     * 
更新方法
     * Test method for {@link com.zhjy.mltx.dao.OrgTypeDAO#updateOrgTypeInfo(com.zhjy.mltx.vo.OrgTypeVO)}.
     */

    
public void updateOrgTypeInfo(String id) ...{
        setOrgTypeVOUpdateInfo();
        orgTypeVO.setId(id);
        
try...{
            orgTypeDAO.updateOrgTypeInfo(orgTypeVO);
        }
catch(Exception e)...{
            assertTrue("
修改通用组织机构失败!", false);
        }
        
//查询
        orgTypeVO = orgTypeDAO.selectOrgTypeInfoById(id);
        assertEquals("
修改通用组织机构失败!", orgTypeVO.getDescription(), "update中海测试");
    }
    
/**//*
     * 
获取数据方法(主健)
     * Test method for {@link OrgTypeDAO#selectOrgTypeInfoById(java.lang.String)}.
     */

    
public void selectOrgTypeInfoById(String id) ...{
        orgTypeVO = orgTypeDAO.selectOrgTypeInfoById(id);
        assertTrue("
无法查看一条通用机构名称信息!",orgTypeVO != null);
        assertEquals("
添加通用组织机构失败!", orgTypeVO.getName(), "add中海测试");
        assertEquals("
修改通用组织机构失败!", orgTypeVO.getDescription(), "update中海测试");
    }

    
/**//*
     * 
测试此通用组织机构是否被引用
     * Test method for {@link OrgTypeDAO#iExistOrgByOrgTypeId(java.lang.String)}.
     */

    
public void iExistOrgByOrgTypeId(String id) ...{
        
boolean isfalse;
        
try ...{
            isfalse = 
this.orgTypeDAO.iExistOrgByOrgTypeId(id);
            assertFalse("
通用组织机构校验错误!",isfalse);
        } 
catch (DataAccessException e) ...{
            assertTrue("
通用组织机构数据操作错误!!",false);
        } 
catch (ObjectNotFoundException e) ...{
            assertTrue("id is null!!",
false);
        }
        
    }
    
/**//*
     * 
删除
     * Test method for {@link OrgTypeDAO#deleteOrgTypeInfo(java.lang.String)}.
     */

    
public void deleteOrgTypeInfo(String id) ...{
        
this.orgTypeDAO.deleteOrgTypeInfo(id);
        orgTypeVO = 
this.orgTypeDAO.selectOrgTypeInfoById(id);
        assertNull("
删除通用组织机构失败!", orgTypeVO);
    }
    
/**//*
     * 
获取数据方法(根据名称)
     * Test method for {@link OrgTypeDAO#selectOrgTypeIdByName(java.lang.String)}.
     */

    
public void selectOrgTypeIdByName(String name) ...{
        String orgtypeid = orgTypeDAO.selectOrgTypeIdByName(name);
        
//assertEquals(orgtypeid, id);
        assertNotNull("未查出来通用组织机构ID",orgtypeid);
    }
    
/**//*
     * 
测试是否重复数据方法
     * Test method for {@link OrgTypeDAO#isRepeatOrgTypeInfo(com.zhjy.mltx.vo.OrgTypeVO)}.
     */

    
public void isRepeatOrgTypeInfo(String name,String id) ...{
        
//setOrgTypeVOUpdateInfo();
        OrgTypeVO orgtypetest = new OrgTypeVO();
        orgtypetest.setId(id);
        orgtypetest.setName(name);
        
boolean isTrue = orgTypeDAO.isRepeatOrgTypeInfo(orgtypetest);
        
//assertEquals("通用组织机构错误数据",isTrue, false);
        assertTrue("通用组织机构错误数据", isTrue);
    }
    
/**//*
     * 
列表方法
     * Test method for {@link com.zhjy.mltx.dao.OrgTypeDAO#orgTypeList()}.
     */

    
public void orgTypeList() ...{
        List list = orgTypeDAO.orgTypeList();
        assertNotNull("
无法获取通用机构名称列表list is null",list);
    }


}
处理过程:
1)把所有以test开头的方法中的方法名称前的test去掉(例如把testOrgTypeList()改为orgTypeList()方法);
2)同时添加一个以test开头的方法,并调用测试方法;这样做主要是因为执行测试时JUnit(除本身特有的方法出外)只执行以test为开头的方法;
3)同时大家注意到我还把测试初始数据放到两个private方法中private void setOrgTypeVOAddInfo()private void setOrgTypeVOUpdateInfo()方法中供调用;
        大家可能认为很简单,就是这样简单的改动带来很大的方便,大家是否注意到,我以后运行测试用例时,只关心public void testOrgTypeInfo() 方法就行了,因为只要各个方法的断言策略定制完成,一般就不会再改动,因此,后期的回归测试还是验收测试,缩小了我们对测试的关注点,同时对后面写 test suite构建整体测试带来极大方便性!其中的好处相信只有使用才能体会!
↑返回目录
前一篇: [200分]我的WEB项目打包发布以后(WAR),我打开里面一看,我加的库文件都不在lib目录下面呢?空的(最好能告诉我详细的步骤)
后一篇: eclipse的工程中如何添加文件?