摘要:本文将带你了解软件测试技术之有效的单元测试,希望对大家学测试技术有所帮助。
本文将带你了解软件测试技术之有效的单元测试,希望对大家学测试技术有所帮助。
前言
对之前的项目进行重构,由于之前的项目中的单元测试大部分都是走走形式,对单元测试疏于管理,运行之后大部分是不通过,这样的单元对项目而言毫无价值,更不要说有助于理解系统功能。这也使我有契机了解到TDD(测试驱动开发)的思想。为了在项目重构中编写有效的单元测试,我查找了有关TDD的一些书籍,《单元测试的艺术》(Roy Osherove著)和《有效的单元测试》(科斯凯拉著)都是有关测试驱动开发的不错的书籍,前者是使用.net语言,后者使用java语言,作为java程序员我自然选择了后者。但实际上作者在阐述一种思想,不论哪种语言都可以读懂,只是平时的习惯,对于熟悉的语言读起来更顺畅。这篇文章也是对书中的内容做一个总结。
一、单元测试代码的可读性
①使用更易懂的API,把你的代码读出来
示例:
//代码一
String msg = “hello,World”;
assertTrue(msg.indexOf(“World”)!=-1);
//代码二
String msg = “hello,World”;
assertThat(msg.contains(“World”),equals(true));
同样断言字符串中包含 World 这个单词,代码一中 使用indexOf 这个取得单词索引位置的API就显得间接许多,而且我们的大脑还需要对表达式进行判断,进一步增加了认知的负担,而contains 方法字面意思就是包含,更符合我们要表达的意思。所以一定要找到更适合易懂的API。同时用assertThat方法替代assertTrue方法,使的整个语句更具口语化,完全可以像读文章一样读出来
②避免使用较底层的方式,比如位运算符(这并不能表示你有多牛 =.=)
示例:
//代码一
public class PlatformTest {
@Test
public void platformBitLength(){
assertTrue(Platform.IS_32_BIT ^ Platform.IS_64_BIT);
}
}
//代码二
public class PlatformTest {
@Test
public void platformBitLength() {
assertTrue("Not 32 or 64-bit platform?", Platform.IS_32_BIT || Platform.IS_32_BIT);
assertFalse("can't be 32 and 64-bit at the same time.",Platform.IS_32_BIT && Platform.IS_32_BIT);
}
}
代码一 要检查的是什么?位运算符结果怎么算?恐怕大部分使用高级语言的程序员很少会用到,这会增加我们的认知负担。
位运算符可能会有效的执行一个程序,但单元测试的代码可读性优于性能,我们应该更好的表达我们的意图,使用布尔运算符来替换位运算符可以更好的表达意图,见示例二。
③不要在测试中对代码进行过度运用防御性策略
1 public void count(){
2 Data data = project.getData();
3 assertNotNull(data);
4 assertEquals(4,data.count());
5 }
第三行代码有些画蛇添足,即使data为空,在没有第三行代码的情况下,测试案例依然会失败,在IDE中双击失败信息,可以快速跳转到失败行,并指出失败原因。所以第三行代码并没有意义,这种防御性策略的真正优势在于方法链中抛出空指针的时候。比如 assertEquals(4,data.getSummary().getTotal()),当此行代码抛出空指针异常时,你无法判断是data为空还是data.getSummary()为空,此时可以先进行assertNotNull(data)的断言。
二、单元测试代码的可维护性
①去除重复,包括结构性重复
1 //代码一
2 public class TemplateTest(){
3 @Test
4 public void emptyTemplate() throws Exception{
5 String template=“”;
6 assertEquals(template,new Template(template).getType());
7 }
8 @Test
9 public void plainTemplate() throws Exception{
10 String template=“plaintext”;
11 assertEquals(template,new Template(template).getType());
12 }
13 }
两个测试方法,一个是测试建立一个空模板,另一个测试建立一个纯文本模板,明显可以发现存在结构性重复,对以上代码进行改进,如下:
1 //代码二
2 public class TemplateTest(){
3 @Test
4 public void emptyTemplate() throws Exception{
5 assertTemplateType(“”);
6 }
7 @Test
8 public void plainTemplate() throws Exception{
9 assertTemplateType(“plaintext”);
10 }
11 private void assertTemplateType(String template){
12 assertEquals(template,newTemplate(template).getType())
13 }
14 }
虽然代码行数没有减少,甚至还多了一行,但是把相同的代码提炼到一处,当它发生变动时只需修改一处,可维护性增强了。
②避免由于条件逻辑而造成的测试遗漏,存在条件逻辑时要在最后加上 fail()方法,强制测试失败
考虑一下,当Iterator 为空的时候,下面的测试方法会失败吗?
1 //重构前
2 public class DictionaryTest{
3 @Test
4 public void testDictionary() throws Exception{
5 Dictionary dict = new Dictionary();
6 dict.add(“A”,new Long(3));
7 dict.add(“B”,”21”);
8 for(Iterator e = dict.iterator();e.hasNext()){
9 Map.Entry entry = (Map.Entry) e.next();
10 if(“A”.equals(entry.getKey()))
11 asserEquals(3L,entry.getValue());
12 if(“B”.equals(entry.getKey()))
13 assertEquals(“21”),entry.getValue();
14 }
15 }
16 }
显然当Iterator为空时,测试并不会失败,这并不符合我们单元测试的目的,进行重构后:
1 //重构后
2 public class DictionaryTest{
3 @Test
4 public void testDictionary() throws Exception{
5 Dictionary dict = new Dictionary();
6 dict.add(“A”,new Long(3));
7 dict.add(“B”,”21”);
8 assertContain(dict.iterator(),”A”,3L);
9 assertContain(dict.iterator(),”B”,21);
10 }
11 private void assertContain(Iterator i,Object key,Object value){
12 while(i.hasNext()){
13 Map.Entry entry = (Map.Entry)i.next();
14 if(key.equals(entry.getKey())){
15 assertEquals(value,entry.getValue());
16 return;
17 }
18 }
19 fail("Iterator didn't contain "+ key);
20 }
21 }
当没有达到预期目的时使用 fail()方法,强制测试失败。
③避免使用sleep方法浪费大量的测试时间
counterAccessFromMultipleThreads 用来测试一个多线程计数器,开启10个线程,每个线程调用计数器1000次,sleep(500),是为了让主线程等待开启的10个线程执行完毕
那么问题来了,如果在10毫秒内所有线程都执行完毕,岂不白白浪费了490毫秒?又或者在等待500毫秒后仍有线程没有执行完毕,那该怎么办?
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标软件测试之测试技术频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号