软件单元测试的测试用例编写方法
发表于:2010-09-10来源:作者:点击数:
标签:单元编写软件
软件 单元测试 的 测试用例 编写方法 MI LY: 宋体; mso-ascii-font-family: " Times Roman?; mso-hansi-font-family: ?Times New Roman??>我在这里用最常用的方法:基本路径测试法来进行单元测试,因为我要用一个实际的例子来进行说明,所以就编写了下面一个
软件单元测试的测试用例编写方法
MILY: 宋体; mso-ascii-font-family: " Times Roman?; mso-hansi-font-family: ?Times New Roman??>我在这里用最常用的方法:基本路径测试法来进行单元测试,因为我要用一个实际的例子来进行说明,所以就编写了下面一个程序模块,就暂且命名为“详细查询模块”吧。
我先写一下基本过程:
1 分析模块函数;
2 在模块中找到相应的关键点(函数);
3 根据第二点,画出模块程序流程图;
4 计算圈复杂度;
5 根据圈复杂度算出测试用例的最优个数;
6 根据路径测试法和圈复杂度写出具体测试用例;
7 进行测试。
void CXIANGXIDLG::OnOK()
{
CoInitialize(NULL);//初始化COM环境
_ConnectionPtr m_pConnection;//连接对象
HRESULT hr;
try
{
hr = m_pConnection.CreateInstance("ADODB.Connection");//创建Connection对象
if(SUCCEEDED(hr))
{
hr=m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;DataSource=shouji.mdb","","",adModeUnknown);//连库
}
}
catch(_com_error e)
{
AfxMessageBox("数据库连接失败,确认数据库连接字符串是否正确");
}
//操纵表
_RecordsetPtr m_pRecordset; //记录集对象
UpdateData(TRUE);
CString strSQL;
if (m_name=="") //路径1
{
MessageBox("用户名不能为空!"); //函数A
}
else {UpdateData(TRUE); //函数B
int lenth=0;
lenth=m_name.GetLength();
if (lenth>12 || length<2) //路径2
{MessageBox("输入的用户名不正确或没有该用户!请重新输入!"); //函数C
}
Else
{
if(m_pipei) //路径3
{
strSQL="SELECT * FROM sj_T_ShouJiKa where 用户姓名 = '"+m_name+"'"; //函数D
}
Else
{
strSQL="SELECT * FROM sj_T_ShouJiKa where 用户姓名 like '%"+m_name+"%'";//函数E
}
try
{
hr=m_pRecordset.CreateInstance("ADODB.Recordset");
if(SUCCEEDED(hr))
{ //从数据库中打开表
m_pRecordset->Open(_bstr_t(strSQL),m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
}
else
{
AfxMessageBox("查询不成功!");
}
}
catch (_com_error e)
{
CString strError;
strError.Format("警告:打开数据表时发生异常。 错误信息: %s",e.ErrorMessage());
AfxMessageBox(strError);
return;
}
while(!m_pRecordset->adoEOF) //路径4
{ //函数F
_bstr_t name="";
_bstr_t shoujikahao="";
_bstr_t tongxinzhishi="";
_bstr_t fuwushang="";
int i=0;
m_list5.DeleteAllItems();
while(!m_pRecordset->adoEOF)
{
name=(_bstr_t)m_pRecordset->GetCollect("用户姓名");
shoujikahao=(_bstr_t)m_pRecordset->GetCollect("手机卡号");
tongxinzhishi=(_bstr_t)m_pRecordset->GetCollect("通信制式");
fuwushang=(_bstr_t)m_pRecordset->GetCollect("服务商");
m_list5.InsertItem(i,name);
m_list5.SetItemText(i,1,shoujikahao);//设置该行的不同列的显示字符
m_list5.SetItemText(i,2,tongxinzhishi);
m_list5.SetItemText(i,3,fuwushang);
m_pRecordset->MoveNext();
i=i+1;
}
}
//关闭连接、释放com资源m_pRecordset->Close(); //路径5
m_pRecordset.Release();
m_pConnection->Close();
m_pConnection.Release();
CoUninitialize();
}
}
}
我们根据这个程序来画出它的程序流程图,如下,是我画好的:
有了图以后我们就要知道到底我们要写多少个测试用例,才能满足基本路径测试。
这里有有了一个新概念——圈复杂度。
圈复杂度是一种为程序逻辑复杂性提供定量测试的软件度量。将该度量用于计算程序的基本独立路径数目。为确保所有语句至少执行一次的测试数量的下界。
公式圈复杂度 V(G)=E-N+2,E是流图中边的数量,N是流图中结点的数量。
从图中我们可以看到,
V(G)=8条边-6结点+2=4
上图的圈复杂图是4。这个结果对我们来说有什么意义呢?它表示我们只要最多4个测试用例就可以达到基本路径覆盖。
下一步我们就要导出程序基本路径。
程序基本路径:基本独立路径就是从程序的开始结点到结束可以选择任何的路径遍历,但是每条路径至少应该包含一条已定义路径不曾用到的边。
我们可以得到基本路径是:
1: A
2: B->C
3: B->D->F
4: B->E->F
下面我们开始写测试用例。
“详细查询测试”做完了吗?没有,因为对于上表的每一个路径,如果结果有不同的,即:结果有对的,也有不对的。那么,我们就还需要进行进一步的测试,下面的工作我就不做了,照搬就是。
单元测试是编写高质量代码的前提,通过编写有效的单元测试即可以保证代码的质量又可以提高开发速度,因为大多数问题都可以通过单元测试发现并解决而不需要部署到应用服务器。纵览网上流行的优秀开源框架,无一不提供完整的单元测试用例。Spring框架便是其中的代表和佼佼者,因为Spring所遵循的控制反转(IoC)和依赖注入(DI)原则使编写有效、干净的单元测试用例变得更加方便、快捷。
编写单元测试用例
本文所采用的案例非常简单,就是对数据库表的增、删、改、查操作进行测试。假设我们有这样一个表url(MySql数据库):
正如你所见,该表只有几个字段,但对于我们的案例来说完全够用。
看到此处,你应该清楚我们是要对数据库操作进行单元测试。如果你是一位经验丰富的开发人员,此时已经会有许多疑问,甚至已经失去继续阅读本文的兴趣:
单元测试不应该直接操作数据库?
对数据库操作的单元测试可以采用DAO模式,Mock一个实现类?
使用内存数据库?
其他?