技术开发 频道

使用Visual Studio 2010特性支持TDD

  【IT168 专稿】在传统的软件开发模式中,我们总是先根据需求编写代码,然后再编写测试程序对其进行测试。这常常使得开发人员在项目的开发后期陷入痛苦的泥潭:当测试程序发现问题后,还要回头再修改当初已经实现的某个类,或者对已经定义好的函数接口进行修改或者扩展。为什么会发生这样的事情呢?这是因为这部分代码的使用需求没有很好的描述。我们在设计类和函数的时候,没有很好的对它们的使用情况进行分析,最终导致代码无法满足测试程序中对代码的使用需求。
 
  为了挽救痛苦挣扎的开发人员,测试驱动开发(Test-Driven Development, TDD)通过编写测试程序,先考虑代码的使用需求(包括功能、过程、接口等),而且这个描述是可执行验证的。通过编写这部分代码的测试程序,对其功能的分解、使用过程、接口都进行了设计。而且这种从使用角度对代码的设计通常更符合后期开发的需求。

  第一篇:Visual Studio 2010 下一个Visual Studio 6.0

  第二篇:Visual Studio 2010 的自定义开始页

  第三篇:Visual Studio 2010中的多显示器支持

  第四篇:Visual Studio 2010中的调用继承树

  第五篇:C# 4.0中的动态类型和动态编程

  第七篇:Visual Studio 2010特性支持Office

  第八篇:Visual Studio 2010的Quick Search特性

  第九篇:Visual Studio 2010中的C++0x新特性

  第十篇:Visual Studio 2010中的C++ IDE增强

  第十一篇:使用Visual C++ 2010创建Ribbon界面

  第十二篇:Visual C++ 2010创建Ribbon界面(下)

  第十三篇:Visual Studio 2010与VS2008全面比较

  测试驱动开发开始流行于20世纪90年代,是极限编程中倡导的程序开发方法之一,其主要思想就是先写测试程序,然后再实现代码使其通过测试。在TDD产生之初,曾经被当做程序员们的救命稻草而受到众人追捧。但是后来在实践过程中人们逐渐发现,由于缺乏相应的开发工具的有力支持,TDD的实施变得困难重重:无法高效地编写测试程序;测试程序写好后,无法自动生成代码框架,开发人员还要用大量的时间来编写实现代码。这些现实的因素都困扰着TDD的发展,让大家有一种TDD“看上去很美”的感觉。

  现在,Visual Studio 2010的即将到来,可以让坚守TDD的开发人员们欢呼了:VS2010的“即用即产生”特性,可以让我们根据测试程序,根据代码的使用情况,快速地反向生成相应的代码。可以说,“即用即产生”特性,给TDD插上了腾飞的翅膀。还等什么,我们一起来体验一下“即用即产生”特性给TDD带来的无限便利吧。

  1. 创建开发项目和相应的测试项目
  首先,我们创建一个基于Visual C#的开发项目GFUDemo_CS,项目模板我们选择Windows->Class Library:


图1 创建项目

  然后,我们在解决方案GFUDemo_CS中添加一个测试项目TestProject1,项目模板我们选择TestProject:


图2 创建测试项目 

  2. 创建测试程序

  按照TDD的流程,我们需要先编写测试程序。在测试项目TestProject1中,我们找到单元测试类UnitTest1,将其修改为AutomobileTest,这就是我们接下来将要使用的测试类。

  [TestClass]
    
public class AutomobileTest
    {
        
public AutomobileTest()
        {
            
//
            
// TODO: Add constructor logic here
            
//
        }
//
}

  然后,我们找到测试类AutomobileTest中的测试函数TestMethod1,将它修改为 DefaultAutomobileIsInitializedCorrectly。在这个测试函数中,我们创建一个全新的类Automobile的实例。这里我们注意到,Automobile类是我们的最终设计目标,但是现在还没有实现,我们就开始使用了。


图3 创建测试函数

  很快我们就发现Automobile下面出现了红色的波浪线,系统提醒我们这个类还没有创建。这里,我们就可以使用Visual Studio 2010的“即用即生成”特性来快速地产生Automobile这个类。我们把鼠标移动到这个类上,VS2010会弹出一个下拉标签,如果我们选择其中的“Generate class for ‘Automobile’”,系统就会按照默认的设置创建一个Automobile类:


图4 “即用即生成”菜单

  当然,我们也可以选择其中的“Generate other”,对新创建的Automobile类的一些参数进行相应的设置。例如,我们可以设置它的访问权限,类型,以及选择所在的项目和文件等等。


图5 设置新类型的参数

  3. 测试类的属性

  在我们的需求分析中,我们设想Automobile有两个属性Model和TopSpeed,在Automobile类的默认构造函数中,这两个属性应该被分别初始化为“Not specified”和-1。我们可以在测试函数中添加如下的语句对这两个属性是否被正确地初始化进行测试:

Assert.IsTrue(myAuto.Model == "Not specified" && myAuto.TopSpeed == -1 );


  同样地,当我们完成了上述代码的输入后,Model和TopSpeed下很快就出现了红色的波浪线,系统提示我们Automobile类没有这两个属性。按照“即用即产生”的原则,我们可以即时为Automobile类创建这两个属性:


图6 创建类的属性

  4. 测试类的构造函数

  在测试项目中,我们新建一个测试方法AutomobileWithModelNameCanStart,在这个方法中,我们以指定的model和topspeed创建一个新的Automobile对象。

[TestMethod]
        
public void AutomobileWithModelNameCanStart()
        {
            
string model = "550 Barchetta";
            
int topSpeed = 199;
            Automobile myAuto
= new Automobile(model, topSpeed);
        }

  同样,我们利用“即用即生成”的特性为Automobile类生成新的构造函数。在这里我们可以发现“即用即生成”功能非常“聪明”,它会根据这个构造函数的使用情况,自动检查参数的类型,然后也会根据参数的名字,选择合适的属性来存储参数的数据。例如在Automobile类中,它就分别选择了前面我们添加的两个属性Model和TopSpeed来存储构造函数的两个参数。

public Automobile(string model, int topSpeed)
        {
            
// TODO: Complete member initialization
            this.Model = model;
            
this.TopSpeed = topSpeed;
        }

  这时我们注意到,当新的构造函数添加后,原有的默认构造函数就没有意义了,在DefaultAutomobileIsInitializedCorrectly测试方法中我们使用了默认构造函数,这时就会出现红色的波浪线提示,不过没有关系,我们可以用“即用即产生”马上为它创建一个默认的构造函数。  

  5. 测试类的成员函数
 
  在需求分析中,我们的Automobile类应该具有一个成员函数Start()和一个属性IsRunning,分别用来启动我们的Automobile和判断它是否正在运行。我们编写Start()函数和IsRunning属性的测试程序如下:

myAuto.Start();
Assert.IsTrue(myAuto.IsRunning
== true);

  因为这两者并没有在Automobile类中实现,所以我们利于“即用即产生”功能,在Automobile类中添加成员函数Start()和属性IsRunning。
 
  到这里,我们的测试程序就全部编写完成了,与此同步的是,我们的目标类Automobile也已经搭建好框架,初具雏形了。并且,更加重要的是,Automobile类的创建是完全基于它的使用情况而创建的,这样就避免了在开发后期因为测试无法通过而修改类的设计。

public class Automobile
    {
        
public string Model { get; set; }

        
public int TopSpeed { get; set; }

        
public Automobile(string model, int topSpeed)
        {
            
// TODO: Complete member initialization
            this.Model = model;
            
this.TopSpeed = topSpeed;
        }

        
public Automobile()
        {
            
// TODO: Complete member initialization
        }

        
public void Start()
        {
            
throw new NotImplementedException();
        }

        
public bool IsRunning { get; set; }
    }

  6. 运行测试程序
 
现在,我们可以从“Test->Run->All Tests in Solution”来运行测试项目中的所有测试,毫无例外的,我们的两个测试都会失败。
 


图7 测试失败

  测试失败并没有让我们“胆战心惊”,相反,我们找到了前进的目标,我们接下来的任务就是修改代码的实现,使得测试通过,让红灯变成绿灯。

  7. 实现代码,通过测试

  在测试报告的帮助下,我们很快就找到了测试失败的原因:默认构造函数没有正确地初始化和Start()函数没有正确地启动我们的Automobile。所以,我们将这两个函数修改如下:

public Automobile()
        {
            
this.Model = "Not specified";
            
this.TopSpeed = -1;
        }

        
public void Start()
        {
            
//throw new NotImplementedException();
            this.IsRunning = true;
        }

  然后,我们再重新运行测试,就会高兴地看到,所有测试都可以通过了,绿灯大开。


图8 测试成功
 

  有了“即用即产生”功能,Visual Studio 2010中的TDD真如“行云流水”般顺畅。

0
相关文章