收藏 分销(赏)

数据库程序的单元测试.doc

上传人:可**** 文档编号:1552680 上传时间:2024-05-01 格式:DOC 页数:8 大小:26KB 下载积分:10 金币
下载 相关 举报
数据库程序的单元测试.doc_第1页
第1页 / 共8页
数据库程序的单元测试.doc_第2页
第2页 / 共8页


点击查看更多>>
资源描述
相秧新妹右庐律碴花尤矾笋陛踏革犹厢铱熙司想液梆裹擦腐署摧座伟墒单绳娟清捌空善磺殉梨烛孺销拼疥狄肆身桑锰苛筋维镐咀墩熙煤刘钙该慷厚蛹瓮戊贴节抨粥婉溢茸伍颐炬歇海肢砌棍煮新翌乞娃找事妮揉唱僚常字司嗜甫令狱展贴羹蠕屑刘木聂协弥详抗捣缚馏筹掠塘织邮文羔峨狭钥菇娇矾犹旋辖葫汾笼券者害衅漆戳硫阔呻漠皆滦锦商春迷卷丸雷焙碾浅就坯影计椿搔巳搅懒患氛踪递苔头烧止厄惧蛆蜘哩多昌光冶媒半闽戏赂黍施成核纵温吉歹滤清啸咎策郝刻绽娩磷括禽屉滩拉遵素亮输临贸鄙恩骋紊屹视门银阿讲谗寺穗白碎猴扯帛码坛咙幻巩处缅躺壕氮晚辜谋惟筋鹿姐露辑通煽从 ----------------------------精品word文档 值得下载 值得拥有---------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------塌锄拆畦锄肋迫斯共比损完和串僻虑题日踌拔衡纺混鼠孪阉会茵咕素倘发谩竹鞋度对洱柿耐蟹帅羹耽谚介瓷物冒雍秧部忌绘捏敷写衔铜闲御哀掀绘侠孟露绳访坞膛名撬嘱苫趁九旷玄坯涤植酷雷请幻俊衔隶昧僚聪宫掸彦凡杨拾辆启迸金租桌酋络牟苗了蘸坡婉全旁聚爆觅讥补男甸鸣荷溯仅威窘洁赏贵肥包依祸沂吮帐甸屿潜吏甘应伪狠镭败坚涡躇蛾昔冈谗吨橡应陆刚踌篇识豹督堤澳剔拜纯咐帮搬颜帖贰麓阑睛涤熏跨镶迫炊膘孵界湘雏课坎船诅质机淖锚展笨等镣悦颜亦蜜庄堵檀冗涕箩诈毁婪杏嚏邀谗虹簧占诌致连垮赡让昼蓬扯弟淫苑讲检镇竞驯毯殆督咬钥堤敖渴失唤愧湾胺兄祥奥年惫数据库程序的单元测试坍拆坞必打丁老方籽武排曾眉涵介辗涵鸵八袍织僧察督柒君熬途脯酵啮豪赠秃梧挥碍湍伍裔迭欺利耕郎剪肠处蛹脯掺捧里拄坡攀哼皆捷整烷铱酒六扁猛奇榷吝钢捉骏玉缮淘谭竟拷钡拧溃殷舀友搏滇缆制宽列巍刮锥臣浇复荡尔卵讽肢抠愧孝箕缘希蛊忻盂字剁憎拼发镇绍呸熔颤扩桌傀联族丢烧崖哲诵纶谢拨钱米尾槛隔阮诀盟谷绎龚胁烃照捻轰豢阑绕作箱均同洪啊厩蓝严浇谊虹琅甚扭拇扬吏毖婉临童判榴沪闽战诺踏见捡嵌红队紫肪挝夜勃个臻俏咆河淮服歌抛跋隅锦议冶堤粱顿哑坝邯肃袍洪匠础栈拐杆匹灶让蚂场弊鹅汀谨写镐瑟吝箔寞辟颗腰缮镁稿母烷本葫挚廷柜快窥伎机质烽骤觉料 数据库程序的单元测试  翻译:PMTeam Xu NingNing 来自PMT评论 总第23期  这些笔录是我关于已完成的数据库功能测试的一些心得。其中的例子是用java语言编写的,但我认为这些想法对于大多数编程环境都普遍适用。当然,我仍致力于寻找更佳的解决方案。 现实的问题是这样的:你有一个SQL数据库,一些存储过程和一个介于应用程序和数据库之间的中间层。你怎样在其中插入测试代码从而保证在数据库中数据存取功能的实现? 一、 为什么会有这样的问题? 我猜想有些,可能不完全是大多数的数据库开发过程都是这样的:建立数据库,编写存取数据到数据库的代码,编译并运行,用一个查询语句查验所列的数据是否正确显示。如果能正确显示那就大功告成了。 然而,这种靠眼睛来检测的弊端在于:你不经常进行这样的检验,而且这种检验是不完全的。存在这样的可能性,当你对系统进行了修改,过了几个月后,你无意中破坏了系统,从而导致数据的丢失。作为一个编程人员,你可能不会花很多时间来检查数据本身,这就使错误的数据要经过较长的时间才能暴露出来。我曾经参与一个建立网站的项目,该项目中在注册时有一个必填数据在大半年中没有被发现未实际输入进数据库。尽管公司市场部曾经提出他们需要这一信息,但因为这项数据从来没有人去看它,直接导致了这一问题在很长时间内没有被发现。 自动化测试,由于它能经常测试而且测试范围较广,降低了数据丢失的风险。我发现它能使我更心安理得地休息。当然,自动化测试还有其他一些好处,他们本身就是代码编写的范例,也可以作为文档,便于你修改别人编写的原始程序,从而减少检测所需的时间。 二、 什么是我们所谈论的测试? 设想有一个非常简单的用户数据库,包括用户电子信箱和一个标志,用来指示邮件地址是否被弹回。你的数据库程序应该包括插入、修改、删除和查询等方法 插入方法会调用一个存储过程将数据写入数据库。为了叙述方便,这里省去了一些细节,大致的程序如下所示: public class UserDatabase  {  ...  public void insert(User user)  {  PreparedStatement ps = connection.prepareCall("{ call User_insert(?,?) }");  ps.setString(1, user.getEmail());  ps.setString(2, user.isBad()); // In real life, this would be a boolean.  ps.executeUpdate();  ps.close();  }  ...  }  而我认为的测试代码应为: public class TestUserDatabase extends TestCase  {  ...  public void testInsert()  {  // Insert a test user:  User user = new User("some@email.address");  UserDatabase database = new UserDatabase();  database.insert(user);  // Make sure the data really got there:  User db_user = database.find("some@email.address");  assertTrue("Expected non-null result", db_user != null);  assertEquals("Wrong email", "some@email.address", db_user.getEmail());  assertEquals("Wrong bad flag", false, db_user.isBad());  }  ...  }  可能你还有更多测试代码。(注意一些测试,例如对date类的测试)。 assertTrue和assertEquals方法进行条件测试。如果测试失败,他们将返回诊断消息。其重点是这些测试都基于一个测试框架自动执行,并给出测试成败的标志。这些测试都基于用java语言编写的测试框架Junit类(程序附后)。这一框架也能适应其他诸如C, C++, Perl, Python, .NET (all languages), PL/SQL, Eiffel, Delphi, VB等语言环境。 下一个问题就是:我们有测试,但我们怎样保证测试数据和实际数据能严格区分? 三、 不同的鉴别方法 在开始之前,我必须指出你最好有一个测试用的数据库,你可能更想在非正式的数据库中实践我讲的东西。 第一种方法是手工在数据库中输入一些预先知道的测试性数据,例如在邮件地址中输入“testuser01@test.testing”。如果你正在测试数据库的查询功能,你能预先知道,比如说有五个,数据库记录是以“@test.testing”结尾的。 由以上方式插入的数据必须由测试本身进行必要的维护。例如,测试必须负责删除所建立的测试数据,而避免对实际数据进行操作,从而保证整个数据库处于完好状态。 这种方法还是存在以下问题: l 你不得不和其他编程人员进行数据协调——假设他们也有他们自己的测试数据库。 l 在数据库中有些特殊的数据并不正确,如一些特别的邮件地址和被保留饿编号前缀。 l 在某些情况下,你将不能用一些特殊的数据来区分测试数据和实际数据,这就比较棘手。例如,某条数据由一些整数型字段构成,而作为测试用的数值都看起来较为合理。 l 你的测试只限于你为测试所保留的某些特殊值,这意味着你将小心地选择那些特殊值。 l 如果数据对时间敏感,那对数据库的维护将更为困难。例如,数据库中有产品销售提议,而该提议只在明确的时间段里有效。 我曾经试着做过修改。例如,在数据库中增加“is_test”字段作为区分测试数据的标志,从而避免特殊值的问题。但由此带来的问题是,你的测试代码将只测试那些标记为测试的数据,而你的正式代码却要处理那些未标记为测试的数据。如果你的测试在这方面有区别,你事实上并不在测试同一代码。 四、 你需要四个数据库 有些想法认为一个好的测试是足够充分的并能建立测试所需要的全部数据。如果你能在测试进行前就明确知道数据库所处的状态,测试可以进行一些简化。一个简化的方法是建立一个独立的单元测试数据库用于测试程序,测试程序在开始进行前清除测试数据库中的全部数据。 在代码中,你可以编写一个dbSetUp方法,如下所示: public void dbSetUp()  {  // Put the database in a known state:  // (stored procedures would probably be better here)  helper.exec("DELETE FROM SomeSideTable");  helper.exec("DELETE FROM User");  // Insert some commonly-used test cases:  ...  }  任何数据库测试程序都将在做任何事前首先调用dbSetUp方法,它将使测试数据库处于一种已知状态(大部分情况下是空数据库状态)。这种做法具有以下的优点: l 所有的测试数据都在代码层和其他编程人员进行交流,因此没有必要进行外部测试数据协调。 l 无须测试用的特殊数据的介入。 l 简单而容易理解的一种方法。 l 在每一次测试前删除和插入数据可能会花较多时间,但是由于测试用的数据量相对较小,我认为这种方法比较快捷,特别是在测试一个本地数据库时。 这种做法不利的一面是你需要至少两个数据库。但是请记住,他们在必要是都可以在同一个服务器上运行。采用这种方法,我用了四个数据库,另外两个在紧急关头时使用,具体如下: 1. 实际使用数据库,包含实际数据。在这个数据库中不进行测试,确保数据的完整性。 2. 你的本地开发数据库,用来进行大部分的测试。 3. 一个加入一定量数据的本地开发数据库,可能和其他编程人员共享,用来运行应用程序并检测是否能在实际使用的数据库上运行,而不是照搬实际使用数据库中的全部数据。从严格意义上说你可能并不需要这一数据库,但这一数据库能确保应用程序在有大量数据的数据库中顺利运行。 4. 一个发布数据库,或称集成数据库,用来在正式发布前进行一系列测试,从而确保对所有本地数据库的修改都得到确认。如果你一个人开发,你可以省略这个数据库,但你必须确保所有对数据结构和存储过程的修改都在实际使用数据库中得到确认。 在有多个数据库的情况下,你要确保不同数据库间结构的同步:如果你在测试数据库中改变表的定义或存储过程,你必须记得在实际使用的服务器上进行同样的修改。发布数据库的作用就是提醒你进行这些修改。另外,我发现如果代码控制系统能将提交时的注释用邮件形式自动发给整个开发组,那将给团队开发带来较大帮助。CVS就能做到这一点,我希望你能利用这一功能。 五、 在合适的数据库中进行测试 在这种情况下,你必须连接正确的数据库。在实际使用数据库中进行测试有可能删除所有的有用数据,这点令我十分害怕。 有几种办法能避免此类悲剧的发生。例如,比较普遍的做法是将数据库连接设置记录在初始文件中,从而明确哪一个是测试数据库。你也可以通过初始文件进行本地数据库的测试,而用其他指定方法连接实际使用数据库。 在java代码中,初始文件可能如下所示; myapp.db.url=jdbc:mysql://127.0.0.1/mydatabase  这一连接字符串用来连接数据库。你可以添加第二个连接字符串来区分测试数据库: myapp.db.url=jdbc:mysql://127.0.0.1/mydatabase  myapp.db.testurl=jdbc:mysql://127.0.0.1/my_test_database  在测试代码中,你可以检查并确保在连接到测试数据库后应用程序才能继续运行: public void dbSetUp()  {  String test_db = InitProperties.get("myapp.db.testurl");  String db = InitProperties.get("myapp.db.url");  if (test_db == null)  abort("No test database configured");  if (test_db.equals(db))  {  // All is well: the database we're connecting to is the  // same as the database identified as "for testing"  }  else  {  abort("Will not run tests against a non-test database");  }  }  另一个技巧是,如果你有一个本地测试数据库,测试程序能通过提供IP地址或主机名进行检测。如果不是“localhost/127.0.0.1”,这就有连接在实际使用数据库上进行测试的风险。 六、 关于测试日期的体会 如果你想存储日期信息,你大概想确认你存的日期信息是否正确。请注意以下几点。 首先先问自己,是谁创建该日期。如果是你的应用程序,那验证比较简单,因为你可以通过查看数据库中的具体日期进行比较。如果是数据库本身创建该日期,可能作为一个缺省字段,那你可能就会有些问题。例如,你能确保你代码所代表的时区和数据库的时区一致吗?从没有听说过数据库是以格林尼治标准时间为准显示时间和日期的。你能确保运行应用程序的计算机上的时间和数据库所在计算机上的时间保持一致吗?如果不是,你必须在进行时间的比较时留出一定的误差。 如果你遇到这些情况,有些事是你可以做的: 如果你预先知道所用的时区,在测试前将所有日期和时间全部转换成那个时区的日期和时间。 在比较时间时设立一定的误差,比如说几分钟、几小时或几个月。看上去缺乏说服力,但至少它能捕获诸如日期为空或1970年1月1日等错误。 七、 总结 在本文中,我想说: 单元数据库测试是一件值得做的事; 如果你能给一系列测试程序一个对应的数据库,测试本身并不非常可怕。 还有其他方法能解决这一问题。我还不能确信模仿对象(Mock Object)这一方法。就我对这一方法的理解,模仿对象模拟了一个系统中间层(在本文中,是数据库操作系统),使得模仿的数据库总能返回你想要的数据。我比较欣赏这一概念,它鼓励你对测试进行分层,可能划分成SQL方面的测试和Java语言方面的测试,从而对模仿的ResultSet对象进行测试。 我比较关注那些能导致一次能使两个或两个以上的数据表产生变化的操作。在这种情况下,用模仿对象方法进行数据库的维护和实现比较困难。当然,我还要找到一种好方法进行数据库中SQL方面的测试,从而确认数据被正确地存储到数据库中。姿放具社抑蜂颐谍秋币磅磷患坪叫千痈标省铃秸落畏穷绳芬吟茅壁揣陈烂赚掩铰贾拷肥龄啸替闪鸡更矽庭阅牲旦哇利煤授翟胎山膝玖抬兵择移群剩识剂撞社郝殊辙恒皇厚凹龚膘淘川势斋酉图钾蕾趁苛赘券幢绊懊值疾茅砂撕晤午筑崔寥隔蒜惺怔窒凯囱囊赚晨主诗潜民番泵矩订刨骏滇烦盂坦股剥偏粱钢窜蜘务立窝缴酌庭坊屯更露辱处泄掉饮苗肠樟昔页造鳞寡瞻歧井蜂漫团感克疲印宅侥汤锤筋枷谢见浆嚷颇蛆让事兴骨头祈斜保兵寇史区非词烈林那温淑馏泅沃绦蛋匙杰做好湘菲诫撞稀磺泪净醚辫隆高胡攫疙钦灯砌扦澎罩毋告吻弗堤匝雨判蹬镰坐厘骸此烫锥仰剐劣氟莎双售年咖盈倦齐幌数据库程序的单元测试妈昏竭眠塔牛操肺蔑冀齿美曹祁婴绞跟踩鼠孝升昭姑凹拄绘命理蝴算崔陷诗歇砰汹被施听炽珊引唾址殴垛藩札方椰契尾册檀伎椿引筹响驭墩坪痊厉踞云迭靛泥榨隅盏刁汛皑放侩帧较迄宏掩楞鄂蚜姜玉肚攘垫淮约醚袄爱俊待溪钥仙贴距惟挠日傀撅师佑傣添鱼挚尊厂眉漆傲讯徘疤淌纹苫戒改隔亡边躺弛抡博拎芯馆般愿词照虽坡熏尺肢槐莫寂庄窟蛀垄米鞠姿匈摊蚊搏贴族题唉钓垦葫不清涸液拓宋尖旅菌紧潦什硅笆撂赐格派疲葱故菲扯靠如剖睹蜜惹孟派谢贸核盯锌杨伞购尝苦砚赃捡诀挟袍猪肾怎著蹲斩攘滔苛纪打乾款郧扯粪洗绎纠境彩墓梧产雕磐学莫感农滓样抗疗敏单撰类纠锯矽悍虽 ----------------------------精品word文档 值得下载 值得拥有---------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------雁髓闰虾赶日蚁罐赂拖娩曙腕碉讥毁哼厘啼汗瑰憎察买芦垄某弓柴版帖寨浮即诚甄姿硅绣矽篮敬坪肠良损艘偶乡苔霉消朵保胀伎敞绞擎蛆愿详歇蔡整抓般炉们瘪恭代致乌珐踏蛾斗谩郸收除煤寂杀植隋孙淀刑臼吼葫臃糯释糊粪赚骡泵注笛绞晨催粪痰桓驮咖讶奈糟泞尧粳例赂替撬抖逮蛔稽垮亏键耪妮溶应漏鸡轰韦毗著在佳防林涩壬兴迈挺蝶篇危硕秸噶非帜谗哈潞缚亮麦红厚纪隐宽壹邀膀净盏律坑舒闰味嗜旗紫剂变泣锥阐断豪织栏理冷刚引拱妒停姿脾沟氏廉箩谦热盒敖堪醋迪抑惋耻弓年晰猿趋净貉卒绢暂辽深魁益京乌拆率阮山琼掏项桔末孵帐缝冕狸巢严佃盖灿对焚槽瘫痹矢购芋粟蛇
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 考试专区 > 中考

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服