------------------
前言 Preface
------------------
本文是第二代测试框架系列文章,同时也是软件工程革命三部曲中的技术文献。
本文展示了Visual Studio中独特的断点调试技术,是目前尚未有人尝试过的断点方式,而且也是您google也找不到的技术。
------------------
测试还是调试?
------------------
测试驱动TDD的提出,有其理论的优势,也有明显的不足,本人的理解是:当我们对项目有六成以上的把握,采用测试先行可以节省代码开发量,否则绝对不建议测试先行(测试先行 不等于 单元测试 等等)。
原因也很简单,如果我们对未来估计不足,不仅系统代码变化很大,而且测试代码变化也很大,盲目采用了测试先行导致增加了工作量。
如果上面的论点是正确的,那么我可以获得下面的论点:项目开发中,测试先行以外,必然存在了测试后行,或者我们非常熟悉的名词——调试。我不知道为啥测试和调试有必要分开,这个就是玩文字游戏,硬把相同的事情用不同的LABEL区分。
那么既然测试后行就是调试,我就应该把调试技术纳入测试框架,于是引入了Breakpoint技术。
------------------
Breakpoint
------------------
传统的调试技术,无非就是在Visual studio里面设几个断点,然后运行中查看。
这让我想起我初中的时候,用qbasic写的人生第一个游戏:Dream of Navigation(当时玩大航海时代玩疯了,于是自己写了一个)。扯远了,提这个只是想说,那时已经有了break point技术了。所以,几乎写程序的人就知道breakpoint。
今天,老弟我就令走不寻常路,介绍一个新的断点技术。
首先看看在c#里面如何使用代码设置断点:
恩,就这么简单!当代码出现了这句话后,在debugger模式下,IDE会自动停在这里了。如果问原因,就是在IL里面插入了一个断点。换句话说,我可以用纯IL的方法实现这个技术,不过既然微软封装了,我就省了。
不知道大伙会不会立刻打开VS,然后写一段测试一下? 有了这个技术,就可以实现VS的任何断点技术,包括:断点条件、断点命中次数、甚至断点宏等。如果不知道这些功能,可以打开IDE,设一个断点,然后鼠标右键点击一下,得到:
平时,我几乎很少用上面的功能,因为实在太麻烦也不直观。如果这些设置能在代码里面完成,调试结束后删除调试代码,那么就更加实用了。于是我就扩展了断点技术。
当然,遇到比较大的问题就是断点位置问题,比如计算命中次数,不同地方的断点对命中次数计算是不一样的,不过有了之前的经验,解决这个问题就很简单了,我只要获得当前断点代码在总代码中的偏移量,就可以获得唯一的位置标识符,然后隔离不同的算法。例如一下就是断点技术中另外一个核心算法:
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![ExpandedBlockStart.gif](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
{
StackTrace stack = new StackTrace();
StackFrame testcaseframe = stack.GetFrame(default_stack_index);
System.Reflection.MethodBase method = testcaseframe.GetMethod();
StringBuilder builder = new StringBuilder();
builder.Append(method.DeclaringType.FullName);
builder.Append(method.Name);
builder.Append(method.IsGenericMethod);
if (method.IsGenericMethod)
builder.Append(method.GetGenericArguments().Length);
foreach (System.Reflection.ParameterInfo parameter in method.GetParameters())
{
builder.Append(parameter.ParameterType.FullName);
builder.Append(parameter.Name);
}
builder.Append(method.ReflectedType.FullName);
builder.Append(testcaseframe.GetILOffset());
return Pixysoft.Security.MD5.GetMD5(builder.ToString());
}
我使用 StackTrace 技术,获取了断点代码的偏移量(GetILOffset()),然后再MD5一下,就得到了当前断点的唯一标识符。
最后,展示一下断点技术的实际应用:
代码
public void test012()
{
string name = " hello " ;
// 设置 立刻中断
BreakPoint.BreakAtOnce = true ;
// 当 name = "hello" 的时候, 中断
BreakPoint.BreakAt(name == " hello " );
for ( int i = 0 ; i < 100 ; i ++ )
{
// 当循环到98次开始 中断
BreakPoint.BreakAt( 98 );
if (BreakPoint.True)
{
Console.WriteLine(i);
}
}
int value = 1 ;
for ( int i = 0 ; i < 3 ; i ++ )
{
value = i % 2 ;
// 当 value 值变化后 中断
BreakPoint.BreakWhen(value);
if (BreakPoint.True)
{
Console.WriteLine(value);
}
}
}
源代码下载:
http://www.boxcn.net/shared/8vpet6yf0d
------------------
后记 Conclusion
------------------
本文和”框架“ 两字相比,简直是雕虫小技,不过Big Game在后头。各位别急着copy paste,也别急着让我出个完美版的XXX,这都仅仅是冰山一角。
希望各位能够继续关注我的TestDriven 2.0 框架,也请继续关注软件工程革命三部曲。我会好好玩一场游戏。
同时,我也希望各位ITer们(当然更多的是IT精英们),在忙着学hibernate / spring、找.net 十大工具、研究一大堆scrum之类名词等时候,试试在人挤人人推人的人流中,停下脚步,回头看看,当别人往左转的时候,试试往右转,之后就会发现原来你能做的比他们更好。期待各位的留言和想法。
鞠躬敬礼!