一个测试的重构

随着TDD流行,单元测试成软件开发重要部分。本文以NUnit为例,介绍在DotNet中为排序算法编写单元测试。先为冒泡排序编写测试,后要为快速插入排序编写时,发现代码重复问题。通过提炼抽象类TestBase解决,这属于Extract Super Class重构方法。

    随着TDD的流行,单元测试越来越成为软件开发的重要组成部分。那么,说到单元测试,大家都会想到NUnit(当然还有CPPUnit等,不过不在本文的讨论范围)。在NUnit中,编写一个测试的Class是很简单的,不需要像JUnit中那样从某个Class继承,这也得益于 DotNet中富有创意的 Attribute 特性。通过Attribute ,便有了不需要从BaseClass继承的 NUnit,便有了不需要使用Xml辅助配置的ORM工具---GroveKit 。在DotNet中,只需要将Class标记TestFixtureAttribute ,这个Class将被NuitFramework发现,并自动调用其中标记有TestAttribute 的方法作为测试方法。所以,在我为一个排序算法编写Test的时候,它大概就是这样的:

   

None.gif using  System;
None.gif
using  NUnit.Framework;
None.gif
None.gif
namespace  Sorter.TestCase
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//**//**//// <summary>
InBlock.gif    
/// 冒泡算法的测试类
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif      [TestFixture]
InBlock.gif    
public abstract class TestSortBase
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
protected  BubbleSorter sorter ;
InBlock.gif         
InBlock.gif        [SetUp]
InBlock.gif        
public void SetUp()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            sorter 
= new BubbleSorter();
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif         
InBlock.gif
InBlock.gif        [Test]
InBlock.gif         
public void TestIntSort()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// some Assert here
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        [Test]
InBlock.gif         
public void TestDoubleSort()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// some Assert here
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        [Test]
InBlock.gif         
public void TestDateTimeSort()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// some Assert here
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        [Test]
InBlock.gif         
public void TestStringSort()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// some Assert here
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        [Test]
InBlock.gif        [ExpectedException(
typeof(ArgumentException))]
InBlock.gif         
public void TestException()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// some Assert here
ExpandedSubBlockEnd.gif
        }

ExpandedSubBlockEnd.gif    }

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />




         
这个测试类看起来工作的让我满意,在我的算法出现问题的时候,总能被它发现。
冒泡排序是最简单的排序算法,接下来我需要为我的 快速插入排序编写单元测试。首先我想到的是,将上面的类中出现的所有 BubbleSorter 替换为 InsertSorter ,但是很明显,你已经闻到了代码的 Bad Smell了。重复的代码总是让人产生厌恶 。
         
我试着将BubbleSorter的声明改为SorterBase,SetUp方法声明为virtual,然后我让我的InsertSorterBubbleSorter继承,并重写了SetUp。这似乎解决了问题,但是很明显,InsertSorterBubbleSorter之间不应该是继承的关系,而应该是兄弟的关系。
       
怎么办呢?也许你早就想到了,提炼出一个TestBase,让InsertSorterBubbleSorter从它继承。没错,我提炼了一个抽象类,这在重构名录中大概叫做Extract Super Class,其实,重构就像是设计模式一样,在你知道它是一种经典的重构之前,你已经在大量使用这种方法了。这个TestBase应该是抽象类,因为它也不应该实例化。还有一点,标记为abstractclass,即使被标记TestFixtureAttribute,并且内部含有Test方法,在执行测试的时候,也会被NUnit忽略。但是,为了减轻NUnit的工作量13.gif,我还是去除了TestBaseTestFixtureAttribute,这样,代码阅读者也不至于产生误解。
       
下面是经过重构后的TestBubbleSorter  

       

ExpandedBlockStart.gif ContractedBlock.gif      /**/ ///<summary>
InBlock.gif    
/// 冒泡排序的测试类
ExpandedBlockEnd.gif    
/// </summary>

None.gif     [TestFixture]
None.gif    
public   class  TestBubbleSorter : TestSortBase
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
protected override SorterBase CreateSorter()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return SorterFactory.GetSorter( typeof( BubbleSorter ) );
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif     }

None.gif



       
至于SortBase是啥样的,我想地球人都知道了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值