构建之法学习(2)

Posted on 2017-04-16 12:53  月落天白  阅读(124)  评论(0编辑  收藏  举报

本周学习的内容是第二章 个人技术和流程

2.1单元测试

你的RP是由你的程序质量决定的。软件是由多人合作完成的,不同人员的工作相互有依赖关系。例如,一个人写的模块被其他人写的模块调用。软件的很多错误都来源于程序员对模块功能的误解、疏忽或不了解模块的变化。如何能让自己负责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质量能得到稳定的、量化的保证?单元测试就是一个很有效的解决方案。

namespace DemoUser
{
    public class User
    {
        public User(string userEmail)
        {
            m_email = userEmail;
        }

        //user email as user id
        private string m_email;  
    }    
}

/// <summary>
/// A test for User (string)
/// </summary>
[TestMethod()]
public void ConstructorTest()
{
    // TODO: Initialize to an appropriate
    // value    User target = new User(userEmail);
    string userEmail = null; 

    // TODO: Implement code to verify target
    Assert.Inconclusive("TODO: Implement code to verify target");
}

[TestMethod()]
public void ConstructorTest()
{
    string userEmail = "someone@somewhere.com"; 
    User target = new User(userEmail);
    Assert.IsTrue(target != null);
}

[TestMethod()]
[ExpectedException(typeof(ArgumentNullException))]
public void ConstructorTestNull()
{
    User target = new User(null);
}

[TestMethod()]
[ExpectedException(typeof(ArgumentException))]
public void ConstructorTestEmpty()
{
    User target = new User("");
}

[TestMethod()]
[ExpectedException(typeof(ArgumentNullException))]
public void ConstructorTestBlank()
{
    User target = new User("     ");
}

if (!m_email.Contains("@"))
{
    throw new ArgumentException();
}

单元测试应该准确、快速地保证程序基本模块的正确性。

单元测试应该在最基本的功能/参数上验证程序的正确性。单元测试应该测试程序中最基本的单元—如在C++/C#/Java中的类,在此基础上,可以测试一些系统中最基本的功能点(这些功能点由几个基本类组成)。从面向对象的设计原理出发,系统中最基本的功能点也应该由一个类及其方法来表现。单元测试要测试API中的每一个方法及每一个参数。单元测试必须由最熟悉代码的人(程序的作者)来写。代码的作者最了解代码的目的、特点和实现的局限性。所以,写单元测试没有比作者更适合的人选了。

2.1.3 回归测试
在单元测试的基础上,我们就能够建立关于这一模块的回归测试(Regression Test)。Regress 的英语定义是:return to a worse or less developed state,是倒退、退化、退步的意思。在软件项目中,如果一个模块或功能以前是正常工作的,但是在一个新的构建中出了问题,那么这个模块就出现了一个“退步”(Regression),从正常工作的稳定状态退化到不正常工作的不稳定状态。在一个模块的功能逐步完成的同时,与此功能有关的测试用例也同样在完善中。一旦有关的测试用例通过,我们就得到了此模块的功能基准线(Baseline),一个模块的所有单元测试就是这个模块最初的Baseline。假如,在3.1.5版本,模块A的编号为125的测试用例是通过了的,但是在新的版本3.1.6上,这个测试用例却失败了,这就是一个“倒退”(Regres-sion)。工程师们应该在新版本上运行所有已通过的测试用例,以验证有没有“退化”情况发生,这个过程就是一个“Regression Test”。如果这样的“倒退”是由于模块的功能发生了正常变化引起的(例如,我们要修改模块,支持电子邮件地址以.name为最后的域名),那么测试用例的基准就要修改,以便和新的功能保持一致。针对一个Bug Fix,我们也要做Regression Test。目的是:
1. 验证新的代码的确改正了缺陷
2. 同时要验证新的代码有没有破坏模块的现有功能,有没有Regression
所以,对于“回归测试”中的“回归”,我们可以将其理解为“回归到以前不正常的状态”。回归测试最好要自动化,因为这样就可以对于每一个构建快速运行所有回归测试,以保证尽早发现问题。单元测试是回归测试的基础。在专注于模块基本功能的单元测试之外,还有功能测试—从用户的角度检查功能完成得怎么样。在微软的实践中,在一个项目的最后稳定阶段,所有人都要参加全面的测试工作,把所有以前发现并修复的Bug找出来,一个一个验证,以保证所有已经修复过的Bug的确得到了修复,并且没有在最后一个版本中“复发”,这是一个大规模的、全面的“回归测试”。

2.2 效能分析工具

DoIt()
{
    //store all words in a big buffer
    ProcessFile()    
    //calculate and store the frequency of each word
    ProcessBuffer()  
    //output top10
    OutputResult()   
}
ProcessBuffer()
{
    //get one word from buffer
    GetOneWord()   
    FreqOneWord()
}
FreqOneWord(word)
{
    Find the word in the array list, 
    If (found)
        Update the frequency
    If (not found)
        Add the word in the array list with frequency =1
}
OutputResult()
{
    //sort the array
    ArrayList.Sort()   
    Output Top10 entry; 
}

2.3 个人开发流程
卡内基梅隆大学(CMU)的能力成熟度模型(CMM和CMMI),是用来衡量一个团队能力的一套模型。

PSP有如下的特点。

不局限于某一种软件技术(如编程语言),而是着眼于软件开发的流程,这样,开发不同应用的软件工程师可以互相比较。
不依赖于考试,而主要靠工程师自己收集数据,然后分析,提高。
在小型、初创的团队中,很难找到高质量的项目需求,这意味着给程序员的输入质量不高。在这种情况下,程序员的输出(程序/软件)往往质量也不高,然而这并不能全部由程序员负责。
PSP依赖于数据。
需要工程师输入数据,记录工程师的各项活动,这本身就需要不小的时间代价。
如果数据不准确或有遗失,怎么办?让工程师编造一些?
如果一些数据不利于工程师本人(例如:花很多时间修改缺陷),我们怎么能保证工程师愿意如实地记录这些数据呢?
PSP的目的是记录工程师如何实现需求的效率,而不是记录顾客对产品的满意度。