发布新日志

  • [论坛] 单元测试思想之测试现有代码

    2006-12-14 11:49:19

      单元测试的最佳方式是边开发边测试,对于已完成部分编码或全部编码的项目,当然也可以测试,测试原则仍然是“越早越好”,例如,如果项目已完成了一半编码,最好停下来,先完成这些代码的测试,然后再用边开发边测试的方式完成后面的编码。
      对于大量已开发的代码进行单元测试往往是很困难的,困难的原因在于代码的可测性可能很低。前面说过,单元测试是一种有效的约束机制,边开发边测试的话,能够保证代码结构的整体良好。已开发但未进行单元测试的代码,如果存在很多业务代码直接写在界面类中、很多不合理的紧耦合等问题,要进行单元测试就很困难,最直接的表现就是代码加入到测试工程时无法编译。这种情况下要对代码进行整理和重构,提高其可测性,这些工作虽然要付出一定时间成本,但提高了代码的整体质量,代码的可扩展性、可复用性都会大幅度提高。
      VU提供了一个工具可以帮助发现需要重构的代码:待测试文件列表,该工具可以将代码文件按引用其他文件的多少进行排序(包括直接引用和间接引用),引用越少,表示代码越底层。将文件按由底层到高层的顺序,一个一个添加到测试工程,每添加一个文件就Rebuild All,如果出现编译链接错误,则可以认定该文件需要整理或重构,导致链接错误的类或文件一般是不应有的耦合对象。
  • 单元测试思想之回归测试

    2006-12-14 11:48:46

      在修改了代码后,可以使用回归测试,对选定的任何类或整个工程执行测试,以检测修改是否破坏了现有代码的功能。
  • [论坛] 单元测试思想之边界测试

    2006-12-14 11:48:00

      在测试用例部分已经说过,设计测试用例时要考虑边界输入和非法输入,这里统称为特殊输入,程序员在编写代码时也要考虑特殊输入,要为特殊输入编写处理代码。在实际工作中,程序员没有考虑到某些特殊输入是很常见的,这也是程序错误的一个重要来源。不幸的是,如果编写代码和建立测试用例时都没有考虑这些输入,那么白盒覆盖也不能自动发现,因为白盒覆盖是以代码为基础的,如果相应的代码根本不存在,白盒覆盖当然不会告诉用户“某某代码未覆盖”。
      特殊输入通常与数据类型有关,例如,如果一个参数是指针,空指针就是一个特殊输入,对于一个整数类型,最大值、最小值、0、1、-1都可以算是特殊输入;另一方面,当输入特殊数据时,如果程序未作合适的处理,运行结果常常是产生异常。根据这两个条件,如果预先为各个数据类型定义特殊值,然后由测试工具自动生成测试用例,使用这些特殊值或其组合作为输入数据进行测试,通常可以发现“未处理特殊输入”而产生的程序错误,这就是边界测试。
      VU具有强大的边界测试功能:完全自动生成测试有例;所有数据类型都可以定义边界值;可以自动过滤部分输入;可以断言输出是否符合某种“不变式”;可以在数据窗口中浏览输入输出数据以判断程序的工作是否正常。
      如果在边界测试中发现了处理某些特殊输入的代码缺失,应补充这些代码,并完成白盒覆盖。

      综上所述,VU并不把功能测试、白盒测试、边界测试作为并列的、重复的测试方法,而是把三者结合为一体,互相补充,形成一个完整的覆盖体系但又绝无重复工作,使用户可以用最小的工作量达到最大的测试完整性。用户在编写代码时,只需要为容易想到的、比较典型的等价类建立测试用例,能够满足编码的需要就行了,可以说,这些测试用例是为编码服务的测试用例。编码完成后,通过白盒覆盖统计和测试用例设计器找出其他等价类并且很容易地建立起测试用例,最后用边界测试自动捕捉“漏网之鱼”。

        为了进一步说明测试完整性,举个例子:假如一个函数,大概有十个等价类,但这个数字并不是显式的,测试人员比较容易想到的,可能只有五个,自己画一下逻辑结构图,做一些代码分析,也许又可以找到二三个,是不是齐全了呢?很难衡量。使用VU,设计测试用例的过程大体是这样的:用户为容易想到的五个等价类建立测试用例,根据语句、条件、分支覆盖,在测试用例设计器的帮助下,找到另两个等价类,根据路径覆盖,又揪出了两个很隐秘的等价类,实现了100%语句、条件、分支、路径覆盖,最后,边界测试又发现了一个意料之外的等价类。当然,这些数字只是一个示意,实现某某覆盖的目的,并不在于覆盖率,而在于尽可能找出所有等价类。

      如果针对代码单元的测试完成了100%语句、条件、分支、路径覆盖,并且执行了边界测试,虽然仍然不能证明所有的等价类都测试到了,但可以肯定的说,已经达到了很高的测试完整性,局部代码中仍然含有错误的可能性很小,当然,设计上的错误除外,这不属于单元测试的范畴。
  • 单元测试思想之白盒测试

    2006-12-14 11:47:23

      这里所说的白盒测试,是指针对程序的逻辑结构来设计测试用例进行测试。白盒测试用逻辑覆盖率来衡量测试的完整性。逻辑单位主要有:语句、分支、条件、条件值、条件值组合,路径。语句覆盖就是覆盖所有的语句,其他类推。另外还有一种判定条件覆盖,其实是分支覆盖与条件覆盖的组合,在此不作讨论。跟条件有关的覆盖就有三种,容易混淆,解释一下:条件覆盖是指覆盖所有的条件表达式,即所有的条件表达式都至少计算一次,不考虑计算结果;条件值覆盖是指覆盖条件的所有可能取值,即每个条件的取真值和取假值都要至少计算一次;条件值组合覆盖是指覆盖所有条件取值的所有可能组合。循环结构一般不考虑循环的次数,而只考虑至少执行循环体一次和不进入循环体两种情况,即把循环结构看作具有进入循环和不进入循环两个会支的分支结构。由于不同的覆盖率具有不同的侧重点,为了保证充分的测试,最好是完成几种覆盖率的组合。VU选择了四种覆盖的组合作为白盒测试指标:语句覆盖、条件覆盖、分支覆盖、路径覆盖。如果这四种覆盖都达到了100%,那么,测试的完整性是非常高的,读者可以比较一下,在使用VU之前,您的项目要求达到什么样的白盒覆盖?实际上又能完成到什么程度?
      白盒测试与功能测试有什么关系呢?可以说,如果功能测试是足够充分的,那么白盒测试就没有必要,从等价类的角度来看,足够充分是指,等价类的划分是完全正确的,并且所有的等价类都测试到了。如何衡量功能测试的完整性呢?人工审核是一个方法,不过这种方式代价较高,并且仍然不能保证结果的准确性。难于衡量测试的完整性是功能测试的主要缺陷,而白盒测试恰恰具有易于衡量测试完整性的优点,两者之间具有极好的互补性。
      在单元测试中,功能测试和白盒测试通常具有这样的关系:如果功能测试足够充分,那么,所有可以覆盖的白盒逻辑单位都已经覆盖,剩下的是不可覆盖的;反过来说,如果有一些逻辑单位未覆盖,并且不能证明该逻辑单位是不可覆盖的,那么,可以认为功能测试不完整:或者等价类的划分不够准确完整,或者有些等价类未测试到。也就是说,白盒覆盖指标可以衡量功能测试的完整性,依据某个未覆盖的逻辑目标,可以发现遗漏的等价类。运行测试后,VU会自动统计白盒覆盖状况,标示出未覆盖的代码、条件、分支及路径,并且提供测试用例设计器来帮助设计可以覆盖遗漏的逻辑单位的测试用例。只要有了第一个测试用例,测试用例设计器就能很好地工作。
      前面说过,使用VU,能达到100%语句、条件、分支、路径覆盖。很多读者会问,对于稍为复杂一点的程序,路径就可能几百上千条,100%覆盖可能吗?那要耗费多少资源?
      任何程序,不管它有多复杂,都不可能脱离客观规律和客观实际。路径是什么?路径是代码的组合,就是程序可能的运行路线。对于一个函数来说,只要输入确定了,程序的运行路线就确定了(局部静态变量是一个特例,它实质上是全局变量,只不过是局部可见而已,因此,也应该看作是一个输入)。从等价类的角度来看,一个等价类里所有可能取值,一般来说覆盖的路径是一样的。我们可以大体上认为:程序的可覆盖路径的数量与等价类的数量基本相等。例如,一个程序,功能是输入人民币小写数值,输出大写字符串,它的路径可能有几百条,但是,我们简单的想一下,就会发现等价类不会超过十个,因此,大体上可以说,可以覆盖的路径不会超过10条。
      至于语句、条件、分支,也可能有一些是不能覆盖的,这些逻辑目标的处理要比路径简单得多。我们说达到100%语句、条件、分支、路径覆盖,是指覆盖可以覆盖的部分,并把不能覆盖的部分识别出来并作适当的处理。
      VU的测试用例设计器具有两方面的功能:识别不可覆盖的逻辑目标,为可覆盖的逻辑目标设计测试用例。测试用例设计器的工作原理是:从现有的测试用例中计算出一个最接近于可覆盖预期逻辑目标的用例作为近似用例,并生成修改提示,依据修改提示对近似测试用例的一个或多个输入数据(通常是一个)进行修改,并视需要修改预期输出,即可获得可以覆盖预期逻辑目标的测试用例。修改提示的主要内容是已满足条件和待满足条件,已满足条件是近似测试用例已经满足的条件,修改近似测试用例时要保证不破坏已满足条件,待满足条件是新的测试用例必须满足的条件。如果待满足条件与已满足条件不冲突,则依据待满足条件修改近似测试用例获得新的测试用例,如果冲突,则该逻辑目标是不可覆盖的,如果条件提示难于理解,可以切换到代码模式下,查看程序逻辑。
      不可覆盖的语句或条件,一般属于冗余代码,建议删除。不可覆盖的分支或路径,则在逻辑结构图中打上删除标识,这种删除不会影响代码。
      有读者会问,如果几百上千条路径,要一条一条识别它能不能覆盖,那可能吗?这种担心是不必要的。只要按照语句覆盖、条件覆盖、分支覆盖、路径覆盖的顺序来完成逻辑覆盖,工作量通常都很小,原因是可确认的不可覆盖的路径会自动剔除。例如,如果一条分支不可覆盖,那么所有“经过”这条分支的路径也肯定不可覆盖,把一条分支删除了,所有“经过”该分支的路径都会自动删除,所以,在完成语句、条件、分支覆盖后(包括把不可覆盖的分支删除),路径数量就不会是庞大的了,未覆盖路径则更少。
      对于复杂的程序,还可以在逻辑结构图中屏蔽一些安全的分支结构。有一些代码形成的分支结构,对其后的程序的逻辑并无影响。例如:
    void Find(CString& str, char ch, int start=0, int end=-1)
    {
        if(end == -1)
            end = str.GetLength();
        ......
    }
    上列的if结构形成的分支结构只用于处理缺省值参数,对后面的代码逻辑无影响,因此是安全的。在逻辑结构图中,与一个复杂的分支结构并列的一个或多个简单的分支结构,通常都是安全的,可以在逻辑结构图中查看各个分支结构对应的代码以判断该分支结构是否安全。安全的分支结构可以屏蔽,以便把注意力集中到值得关注的部分。屏蔽安全的分支结构也会使路径的数量大幅度减少。前面所说的人民币小写转大小的程序,在删除了不可覆盖分支,屏蔽了安全的分支结构后,路径只剩下不到十条,与等价类的数量是接近的。
      如上所述,在VU的逻辑结构图和测试用例设计器的强大功能的支持下,实现100%语句、条件、分支、路径覆盖并不困难。毫无疑问,这种覆盖率是空前的,但是,即使达到了这种覆盖率,也还不能保证所有的等价类都得到了测试。
  • 单元测试思想之功能测试

    2006-12-14 11:44:44

      对于一个代码单元,首先要测试它的基本功能。功能就是在某种输入时应该产生某种确定的输出。对于一个代码单元,它的可能输入通常是无穷的,显然,把输入的所有可能取值都进行测试,是不可能也是无意义的,我们应该用一定的规则选择有代表性的数据来建立测试用例。要考虑的输入主要有三种:正常输入,边界输入,非法输入,每种输入还可以分类,也就是平常说的等价类法,每类取一个数据作为输入数据建立测试用例,如果测试通过,可以肯定同类的其他输入也是可以通过的。如果等价类的划分是准确且完整的,并且每一个等价类都进行了测试,那么,可以说这个代码单元经过了充分的测试。下面举例说明: 
      正常输入
      例如字符串的Trim函数,功能是将字符串前后的空格去除,那么正常的输入可以有四类:前面有空格;后面有空格;前后均有空格;前后均无空格。
      边界输入
      上例中空字符串可以看作是边界输入。
      再如一个表示年龄的参数,它的有效范围是0-100,那么边界输入有两个:0和100。
      非法输入
      非法输入是正常取值范围以外的数据,或使代码不能完成正常功能的输入,如上例中表示年龄的参数,小于0或大于100都是非法输入,再如一个进行文件操作的函数,非法输入有这么几类:文件不存在;目录不存在;权限错误。
      如果输入有多个数据,还要考虑这些数据之间的关系,即等价类还要包括数据的组合。
      要人工找出所有的等价类通常是很困难的,但使用VU,通常不需要这样做,只要为容易想到的、比较典型的等价类建立测试用例就行了,后文会有进一步的论述。
      VU自动生成测试代码,用户只需要在测试用例编辑器中填写输入输出的数值即可:
      参数:系统已生成参数的声明,并且,不管是对象、引用、还是指针,甚至指针的指针,都生成对象,VU在调用这些参数时,对于引用、指针或指针的指针,会自动作出适当的处理。对于基本数据类型或定义了赋值操作符的高级数据类型,用户只需将参数的值直接填在"="后面;对于高级数据类型,则可以像普通代码一样,给结构的各个域赋值,或者调用对象的构造函数或其他初始化函数进行初始化。
      成员变量:可以用点操作符直接为成员变量赋值,当然,如果成员变量本身也是高级数据类型,则可以像普通代码一样,调用该成员变量的初始化函数。
      全局变量:如果全局变量在测试代码中是可见的,则直接引用就行了。
      外部数据:外部数据通常需要手工准备,例如文件中的数据或数据库中的数据。
      前置操作:可以用点操作符直接调用成员函数。如果前置操作是众多测试用例公用的,可以写在测试类的BeginCase()函数中,如果有多种不同的前置操作,还可以通过传递不同的参数来控制BeginCase()的行为。
      预期输出部分的语法与输入部分完全相同,输出可以是0项,1项或多项,每项输出的计算结果,都必须是布尔表达式。如果输出难于预先确定,或者比较复杂,可以在运行测试后再确认。
      从上述可以看出,测试用例编辑器可以适应很复杂的测试用例的编辑。只要一个测试用例已编辑完毕,第二个及更多的测试用例就很简单了:选定一个现有的测试用例,由系统自动拷贝,用户再对部分数值进行修改就行了。由于各个测试用例之间的差别通常很小,这种方式可以很快建立测试用例集。
      测试用例编辑器还具有代码模式,很特殊的情况下,可以切换到代码模式下直接编辑代码。
  • [论坛] 单元测试思想之测试用例

    2006-12-14 11:43:56

      测试用例是什么?对于单元测试来说,一个测试用例,就是设定输入数据,运行被测试函数,然后判断实际输出是否符合预期。
      输入数据就是前置条件,就是被测试函数执行之前的相关数据的初始值,具体来说,就是被测试函数可能要读写的数据的初始值。函数可能要读写的数据有哪些?首先是参数,这个容易理解;第二是成员变量,前面说过,我们把成员变量作为函数输入输出的一部分,对于一个函数来说,通常不需要考虑所有的成员变量,而只考虑该函数要读写的成员变量;第三是全局变量;第四是外部数据,如保存在文件、数据库中的数据。一个函数无论多复杂,都无非是对这几类数据的读取、计算和写入。后两类数据比较少用,我们在测试中主要考虑的是前两类。除了数据方面,有时候,在执行一个函数之前,还需要先执行其他操作以便设置一些必需的环境,我们把这种操作叫做前置操作,也算是输入的一种吧。总结一下,测试用例的输入包括以下五类:参数、成员变量、全局变量,外部数据,前置操作。
      测试用例的输出就是后置条件,就是被测试函数执行之后的相关数据的结果值,包括:返回值,输出参数,修改了的成员变量,修改了的全局变量、修改了的外部数据。通常,在测试用例中,要自动判断输出是否符合预期,如果不符合,则自动报告错误。
      可以看出,测试用例定义了函数执行的前提条件,定义了函数执行后的应有的结果,也示出了如何使用该函数,因此,测试用例事实上也是详细的规格说明,并且是可执行的、自验证的规格说明,是很好的文档,客户通过阅读测试用例,通常可以很清楚地了解代码的功能和使用方法。
      好的测试用例应该是一个集合,该集合完整地定义了程序的行为,我们称为测试用例集。测试是否充分,就是指测试用例集是否完整。
      不要指望完全依靠由测试工具自动生成测试用例。单元测试最重要的是测试代码单元的功能是否正确,而测试工具是不可能自动了解程序功能的。
        设计测试用例是测试工作最费时,最困难的工作,要用人工方法设计出完整的测试集,常常是做不到的。幸运的是,使用VU,只要依据程序的功能,人工设计最容易想到的、典型的测试用例就行了,VU会统计白盒覆盖状况,并提供测试用例设计器帮您设计剩余的用例,最后,还提供自动边界测试捕捉“漏网之鱼”。
  • 单元测试思想之如何编写测试代码

    2006-12-14 11:43:07

      使用VU时,测试代码是自动生成的,但了解手工编写测试代码的方法,有助于更好地实施单元测试。这里用一个简单的例子,说明如何编写测试代码进行单元测试。可以用一个简单的方式来组织测试代码:一个类对应一个测试类,一个函数对应一个测试函数。

    产品类:
    class CMyClass 
    {
    public:
        int Add(int i, int j);
        CMyClass();
        virtual ~CMyClass();

    private:
        int mAge; //年龄
        CString mPhase; //年龄阶段,如"少年","青年"
    };

    建立对应的测试类CMyClassTester,为了节约篇幅,只列出源文件的代码:
    void CMyClassTester::CaseBegin()
    {
        //pObj是CMyClassTester类的成员变量,是被测试类的对象的指针,
        //为求简单,所有的测试类都可以用pObj命名被测试对象的指针。
        pObj = new CMyClass();
    }

    void CMyClassTester::CaseEnd()
    {
        delete pObj;
    }
    测试类的函数CaseBegin()和CaseEnd()建立和销毁被测试对象,每个测试用例的开头都要调用CaseBegin(),结尾都要调用CaseEnd()。

    接下来,我们建立示例的产品函数:
    int CMyClass::Add(int i, int j)
    {
        return i+j;
    }
    和对应的测试函数:
    void CMyClassTester::Add_int_int()
    {
    }
    把参数表作为函数名的一部分,这样当出现重载的被测试函数时,测试函数不会产生命名冲突。下面添加测试用例:
    void CMyClassTester::Add_int_int()
    {
        //第一个测试用例
        CaseBegin();{ //1
        int i = 0;    //2
        int j = 0;    //3
        int ret = pObj->Add(i, j); //4
        TEST_ASSERT(ret == 0);     //5
        }CaseEnd();                //6
    }
      第1和第6行建立和销毁被测试对象,所加的{}是为了让每个测试用例的代码有一个独立的域,以便在多个测试用例中使用相同的变量名。
      第2和第3行是定义输入数据,第4行是调用被测试函数,这些容易理解,不作进一步解释。第5行是预期输出,它的功能是当实际输出与预期输出不同时自动报错,TEST_ASSERT(exp)是一个断言宏,表示当exp的计算结果为真时,测试通过,否则,输出报告错误的信息。
      示例中的格式显得很不简洁,2、3、4、5行可以合写为一行:TEST_ASSERT(pObj->Add(0, 0) == 0);但这种不简洁的格式却有很大的优点,因为它一目了然,易于建立多个测试用例,并且具有很好的适应性,同时,也是极佳的代码文档。
      建立了第一个测试用例后,最好编译并运行测试,以排除语法错误,然后,使用拷贝/修改的办法建立其他测试用例。由于各个测试用例之间的差别往往很小,通常只需修改一两个数据,拷贝/修改是建立多个测试用例的最快捷办法。
      
    上面是一个最简单的例子,下面再举一个涉及成员变量的例子,这是产品函数:
    void CMyClass::Grow(int years)
    {
        mAge += years;

        if(mAge < 10)
            mPhase = "儿童";
        else if(mAge <20)
            mPhase = "少年";
        else if(mAge <45)
            mPhase = "青年";
        else if(mAge <60)
            mPhase = "中年";
        else
            mPhase = "老年";
    }

        这是测试函数中的一个测试用例:
        CaseBegin();{
        int years = 1;
        pObj->mAge = 8;
        pObj->Grow(years);
        TEST_ASSERT( pObj->mAge == 9 );
        TEST_ASSERT( pObj->mPhase == "儿童" );
        }CaseEnd();

      前面说过,如果以函数作为测试单元,成员变量的初始值可以看作是输入数据的一部分,其结果值是输出数据的一部分。示例中,首先设定成员变量mAge的初始值,运行被测试函数,在预期输出中,断言成员变量mAge的结果值。如果需要,运行被测试函数前还可以调用其他成员函数,例如:执行被测试函数前可能需要读取文件中的数据保存到成员变量,或需要连接数据库,这些操作称为前置操作。
      为了访问私有成员,可以将测试类定义为产品类的友元类。例如,定义一个宏:
      #define UNIT_TEST(cls) friend class cls##Tester;
      然后在产品类声明中加一行代码:UNIT_TEST(ClassName)。

      实际上,测试代码中还可能涉及到其他数据,例如全局变量、文件中的数据,或数据库中的数据,后文会作进一步的论述。
  • 单元测试思想之单元测试的实施

    2006-12-14 11:42:21

      单元测试由谁来做?单元测试由测试部门来做还是由开发部门来做,是一个引起广泛争论的话题。我们的观点是:由测试部门和开发部门共同来做:测试部门负责制定规范、培训,并检查测试效果;由开发部门负责具体的实施,最好是边开发边测试。
      测试部门可能不具备实施单元测试的足够人手,即使测试部门有足够的人手,即使项目时间允许,完全由测试部门实施单元测试也会造成资源的较大浪费,因为测试人员要花很多时间来重新理解代码,同时,充分的单元测试通常会发现很多细小的错误,程序员修改代码时,又要再一次理解代码;另一方面,如果等编码基本完成再由测试部门进行单元测试,也就不能发挥单元测试对代码整体结构的约束效果,测试部门拿到代码时,往往会发现难于测试。当然,已经完成编码的项目也不是不能进行单元测试,只不过可能要花费一定的时间成本对代码进行整理重构,后文会有进一步的论述。
      由开发人员实施单元测试,当然也有问题,主要有:一是程序员可能不喜欢做单元测试;二是开发部门可能担心影响开发进度;三是由于思维定势的原因,不容易保证测试的完整性。我们在设计VU的过程中,充分考虑了这三个问题,提供了切实可行的解决方法和工具。
      很多开发人员不喜欢做单元测试,甚至抵制单元测试,对于这种现象,常见的说法是程序员太自信,觉得自己的代码不会有错,所以不愿意进行单元测试。这种说法就好象在说程序员“自以为是,不负责任”,所以不愿意做单元测试。事实是这样的吗?作为程序员,我们自己并无这种心理,也调查过一些程序员,没有谁真的有这种心理,实际上,哪个程序员没有翻江倒海地排查一个小小错误的经历?谁写的代码也不能保证毫无错误,人不是机器,即使编程时思维缜密到没有任何疏漏,也还可能有“笔误”呢。那么,程序员为什么不喜欢做单元测试呢?我们认为,主要还是程序员的工作特点造成的。编程是创造性的工作,编程的最大乐趣就在于看到了自己的劳动成果出现在眼前,这就使程序员常有一种“立即实现”的冲动;另一方面,程序员的思维往往是跳跃向前的,当程序员开始了编程思路之后,一般就不愿意中断思路,花较多时间去编写测试代码了;再一方面,跟测试工具也有一定关系,一般的单元测试工具只显示“通过”,“失败”两种状态,相对而言,在产品工程中直接观看代码的运行结果更有吸引力,更容易产生成就感。
      VU在设计上,力求让程序员自然地喜欢单元测试。一方面,VU自动生成测试代码,不需花费时间、中断思路去编写测试代码;另一方面,VU全方位地示出代码的行为:显示各种数据的输入输出值,显示不同输入时程序所执行的代码;画出逻辑结构图及不同输入时程序的执行路径,程序员可以随时“欣赏”自己的劳动成果;再一方面,VU还帮助程序员快速地排除错误和高效地调试,尽可能减少程序员查找某种错误的时间,使程序员的思维始终集中在程序逻辑上。VU的这些功能,使测试工作费时极少,同时又提高了编程的效率,总体来说,边编码边用VU进行测试,在达到完整测试的同时,还能大幅度减少开发时间。
      VU具有强有力的保证测试完整性的功能:轻松完成100%语句、条件、分支、路径覆盖,提供详尽的测试报告和待测试文件列表,随时可以检验测试效果、找出遗漏代码或未完成覆盖的代码,保证测试的完整性。
      在具体的实施过程中,可以根据实际情况调整测试部门和开发部门的分工,例如,如果测试部门人手充裕,也可以由开发部门边开发边完成功能方面的测试,由测试部门完成白盒覆盖和执行边界测试。

      单元测试的“单元”一般是指函数或类。以类为测试单元,如果类比较复杂,测试会变得很复杂,即使是三五个成员变量,十个八个成员函数这样一个很普通的类,要考虑清楚类的功能,以类为考核对象进行完整的测试,也是很不容易的。我们认为,以函数为测试单元,更符合简单实用的原则。面向对象的测试与面向结构的测试的主要区别在于,对象是有状态的,面向对象的测试要考虑对象的状态。对象的状态是什么?简单点说就是成员变量的值,执行了某个操作后,对象的状态有了变化,也就是对象的成员变量的值有了变化,我们可以把对象的状态作为函数的输入输出的一部分:执行操作前对象的状态也是一种输入,执行操作后对象的状态也是一种输出。如果对象的每一个操作,其输出都是正确的,那么,可以肯定这个对象在任何时候,其状态都是正确的。

      总的来说,单元测试越早越好。早到什么程度?XP开发理论主张测试驱动开发,先编写测试代码,再进行开发,这样的话,单元测试就不仅仅是测试,还是一种设计了。事物总有两面性,这种方式不便于使用测试工具自动生成测试代码,因为测试工具要先了解被测试对象的基本信息才能生成测试代码。我们主张,先编写类的声明,然后生成该类的测试类,先编写函数的声明,然后生成对应的测试函数,编写产品函数的代码时,每写一个功能点都运行测试,随时补充测试用例,这样可以最高效。

      单元测试一般测试底层的业务类,中层的控制类,一般不测试边界类(界面类),所以不要把业务代码直接写在边界类里。

      除了很简单的函数,例如GetMember()/SetMember(),其他函数都应该测试,而不要以是否公有来决定是否测试,因为私有函数也可能很复杂,同样可能隐藏着错误。VU使用一种简单的机制来区隔需测试的函数:在源文件中编写实现代码的函数视为需测试的函数,在头文件中编写实现的函数(一般是简单的内联函数)视为不需要测试的函数。
  • 单元测试思想之单元测试的效益

    2006-12-14 11:41:26

      不增加人力投入,不改变开发流程,不延长项目时间,不提高管理成本,如果要较大幅度地提高软件产品的质量、降低开发测试及后期维护的成本,那么,单元测试可能是最好的选择。
      简单地说,单元测试的效益主要表现在:
      1、保证局部代码的质量。单元测试在隔离的前提下,分别对各个代码单元进行测试,能够达到其他测试不可能达到的测试完整性,从而保证了局部代码的质量。只有局部代码的质量得到了保证,代码的整体质量才可能得到保证。
      2、保证代码的整体结构良好。要对代码进行单元测试,最起码的前提是代码能够隔离,也就是说,要具有一定的可测性,因此,单元测试是一种有效的约束机制,这种机制将保证代码具有良好的整体结构。例如,如果把业务代码直接写在界面类中,将很难进行单元测试,随意的不合理的紧耦合也会造成难于测试,单元测试使这些不好的特性得于及时发现,从而很容易进行修正。可以说,可测性是高质量代码的最重要的特性,不具有可测性,也就无法衡量代码的正确性,而有了可测性,也就在一定程度上保证了代码的可扩展性、可复用性。
      3、单元测试使排除代码错误的成本最小化。排除错误的代价随着时间的推移呈指数级数上升,并且,有很多细小的代码错误只有通过单元测试的手段才能发现。
      4、单元测试大幅度降低了后期测试和升级维护的时间成本。如果代码经过了充分的单元测试,集成测试和系统测试就只需要关注设计方面的问题。自动回归测试也大量降低升级维护成本。
      5、单元测试自然地使开发流程变得“敏捷”,可以适应频繁变动的需求,因为整体结构良好的代码具有较好的可扩展性,自动回归测试又能保证修改不会引入新的错误。

      对程序员来说,单元测试也有利于养成编写局部代码时的缜密的思维习惯,以及提高设计能力。

      本文所说的方法和技术,具有“简单实用”的特征,对于企业来说,不需要增加额外的人员就可以实施,对于某一个项目来说,不需改变原来的开发流程来适应单元测试,反过来,单元测试会自然促进开发流程的改进;对于开发人员,也没有特殊的要求,反过来,单元测试会促进开发人员进一步提高开发能力。
  • [论坛] 两个傻子的爱情(看完我都哭了)

    2006-12-05 12:55:35

    从前有这样的一个爱情故事,故事的主角是两个傻瓜。男的好傻,傻的只知道说疯话,女的
      也好傻,傻的只知道用那双无神的眼睛看着男的,笑,傻笑。
      两个人本来不认识,他们一个天南,一个地北。家里人嫌他们傻,都抛弃了她们
      ,任他们四处流浪。男的从南往北走,女的从北往
      南走,流浪,流浪……。男的以前并不傻,而是因为在工地上干建筑的时候被砖砸中了头,
      从那以后就傻了。女的以前也不傻,考大学的时
      候她考了全市第一名,然而她的名字却被一个有钱人给顶替了,从那以后女的就不再说话,
      不再理自己的父母,后来也傻了。
      不知道走了多长的时间,男的身上的那身衣服变的肮脏不堪,鞋子也露出了那漆黑的脚指头。女的身上那身红衣服已经变成了灰色,散乱的头发上还有几根枯黄的杂草,但是脸还是白的,出奇的白,手里拿着一个矿泉水瓶,冲着路人们傻笑。两个人是在一个黄昏相遇的他们共同发现了垃圾桶里的那块发了霉的面包,一同身手去抓那个面包,两个人的头碰到了一起,男的冲女的狠狠地瞪了一眼,女的冲男的傻笑。男的还是胜利了,他抢到了面包,张开那黑紫色的嘴狠狠的咬了一口,女的没有动,只是傻傻地看着男的,傻傻地。男的看了一眼女的,眼神中没有一点光,女的只是看他,喉咙里不停的咽着唾沫,男的停止了啃面包,开始看着女的,傻傻地盯着,两个傻子就这样看着,男的没有表情,女的傻笑。男的把面包给了女的,男的竟然把面包给了女的,女的也抱着那剩下的 半块干面包啃了起来。男的转身走了没有回头,当他回到自己睡觉的那个废厂房的时候,转身看到了女的,女的一直跟着他,一直跟到了这里,女的还是冲男的傻笑,她们不说一句话,女的便跟傻子住在一起了,晚上睡觉的时候,男的感觉身上很温暖,从来没有过的,女的一直搂着男的,女的睡觉时候很死,睡觉的样子真的不像个傻子。
      两个傻子就这样住到了一起,白天两个人一起去大街上拣东西填饱肚子,晚上就一起回来睡觉,日子就这样一天天过去了。那天晚上男的不知道是在哪拣了一个戒指,生了绿锈的戒指,男的给女的带上了,女的一直冲男的傻笑,那晚笑的更是厉害,女的的笑声撕裂了整个安静的夜。后来笑出了泪,女的哭了,第一次哭了,搂着男的哭了,不明不白的哭了。男的好像无动于衷,脸上依然是没有表情。
      后来女的病了,从来没生过病的女的病了,而且很严重,早晨她没有起来陪男的一起去拣吃的,没有冲男的笑,男的自己出去了,中午男的竟然例外的回来了,手里拿着一瓶新的矿泉水和一个新的面包,他是回来看女的的,男的脸上挂了伤,手指头也青了,鼻子下面还有两道血痕。男的是在抢面包和矿泉水的时候被小摊的老板打的。女的闭着眼睛,还是没有像往常一样冲男的傻笑。男的把面包送到女的嘴边,女的没有吃。女的快不行了,身上发着高烧,已经昏迷了,男的脸上头一次有了表情,慌乱的表情,男的跑了出去,看见一身穿绿警服的人就哭了起来,男的哭了,也是第一次哭了,嘴里喊着:救救我的女人,救救她绿军装一脚踹开了男的,骂道:滚一边去,疯子,我他妈真倒霉,出门这么不顺呢!男的仰面倒在了地上,绿警服狠狠地朝男的小肚子踹了几脚,男的撒了手,绿警服朝男的吐了口吐沫,走了!男的好久才从地上爬起来,脸上的泪已经干了。
      男的把女的背到了街上,街上人很多,但没人注意他们,注意的也只是冷冷地瞅几眼,然后继续赶自己的路。傻子把女的放在路边上,无助的看着行人。女的呼吸已经很微弱了,傻子从路边拣了一个破玻璃片,破玻璃片有着锋利的尖,露着寒光,男的抬起女的那瘦弱脏兮兮的手臂,朝她的手腕狠狠地割了下去,血喷了傻子一脸,傻子大笑,狂喊:“哈哈,我杀人了,你们看我杀人了……”救护车终于来了,女的被抬走了,围观的人们唾弃着男的,骂着男的,然后都散去了。女的最终还是死了,失血过多,女的在医院还没呆上一个小时就被抬进了停尸间,女人走的时候脸上的表情是笑着的,手指上还戴着那长满铜锈的戒指。男的等了好长好长时间,女的再也没有回来,没有回来冲他傻笑,男的哭了,哭的那样痛快,整个夜晚都被男的的哭声掩盖了,然而谁也没有注意到这哭声。
      还是在那个他们相遇的那个垃圾桶旁边,人们发现了男的的尸体,男的脸上的笑容已经僵住了,怀里抱着一个发了霉的面包和一个没有开瓶的矿泉水......
  • [论坛] 爱你,只要你幸福,不需要你记得我

    2006-12-05 12:51:40

    寒冷的二月,山中茫茫的雪中,一男一女艰难的移动着,他们都是户外运动的爱好者,相约进山看雪,途中意外碰到暴风雪,迷了路。

    女人很喜欢男人,他们之间没有表白过,因为之前,女人仅仅是从男人的眼神中,捕捉到喜欢的信息,但是不确定。他们两个都是骄傲而怕受伤的人,因为不确定,所以不表白。

    大雪中,他们手拉着手,说着鼓励的话,在齐膝的雪中艰难的前进,不停的走着,常常走不了几步就会摔交,衣服已经湿透了,被冷风一吹,两个人都嘴唇青紫。

    体力消耗很大,但女人仍然边走边笑,男人看着女人,轻松不少。尽管都在微笑,但是他们知道,死神正一步步向他们逼近。已经三天了,周围仍然是一望无际的雪地,体力已经透支,最糟糕的是,食物也越来越少了。为了生存,他们把所有的食物都集中到了女人的背包里,由女人好好规划,控制每天的食量,以应付最糟糕的情形。

    更不幸的事情发生了,由于雪太深,在路过一片树林时,女人掉进雪洞里扭伤了脚,整个腿肿了起来,每走一步都要忍住巨痛。男人已经极度疲惫了,没可能背上女人前进,而且,女人也拒绝男人背她,她很清楚,这样的话,他们会一起死在山上。

    斟酌再三,只能由男人独自前行,找到出山的路,寻求救援。男人为女人支好了帐篷,安顿好。 他们整理了彼此的背包,女人告诉男人"还剩下八块压缩饼干,咱们一人块",随后说"你出去帮我烧点水好吗?"男人烧好水送进帐篷来,女人说饼干分好了,装在两个包的头包里,男人摸了摸两个背包的头包,凭感觉,的确是一样多。他拉着女人的手说"等着我,我马上回来"。

    直到这时,他们仍然没有向对方表达自己的爱恋,他们都是理智的人,这种情况下,可能一分手就是永别,如果表白之日就是永别之日,未免太过残忍。男人根本不知道自己能不能走出去,如果,他们中只有一人能生存,那何必让对方用一生的时间,去忘记一个逝去的爱人呢?记得一个普通的朋友就足够了。

    女人无限依恋的看着男人"我等你,我知道你能走出去" 男人站起身,替女人盖好睡袋,转身。每走一段路,男人都做下记号,他一心想着找到救援,回去接女人,饿了,啃一口饼干,渴了,吃两口雪。男人的速度越来越慢,他提醒自己,不能停,只要停下就意味着死亡,那女人也就没救了,他努力坚持,他告诉自己,一定要出去。终于,男人耗尽了最后一丝气力,倒下,失去知觉前,他想,女人的食物还够吗?还能撑住吗?

    醒来,男人发现自己躺在救援队的帐篷里,朋友发现他们没有按时出山,救援队已经进山搜救很久了。其实救援队一开始并没有发现男人,他们先找到女人的帐篷,然后顺着男人留下的记号 ,找到几乎冻僵奄奄一息的男人。 男人的体温渐渐恢复,他问"她呢",大家不语,他突然发现,救援队的成员眼角都隐隐有着泪光。男人一呆,"告诉我,她呢",挣扎着要出去找她。救援队长用颤抖的声音说"别找了,她不在了,我们发现她的时候,已经去了,可能是出去融雪烧水,没力气回到帐篷,冻死了"
    ……

    三年后,男人结婚了,是一个和女人一样喜欢户外运动、喜欢笑的可爱女孩。女人走后,这个女孩陪男人走过了最难受的日子,男人逐渐快乐起来,有了感情,两人走到了一起,有时,他们也会一起怀念惋惜女人的逝去,也更珍惜现在的感情。

    当年的救援队长参加了他的婚礼。

    婚礼后,队长来到女人的墓地,女人在照片上,笑容依旧美丽。队长对女人说"你放心吧,他结婚了,很幸福"。 队长流泪了,其实,当年,队长说谎了。 女人不是冻死的,救援队发现她的时候,她好好的躺在帐篷里,睡袋盖的很好,男人替她盖好的,她舍不得动。 女人是饿死的,打开她的头包,只有几块平平的石板,没有什么压缩饼干,剩下的压缩饼干,不是八块,只有四块而已。女人,把剩下的所有物都留给了男人,她真的,很爱他。 队长发现女人的时候,她早已经僵硬的手中紧紧攥着一张小纸条:"我肯定撑不到他回来了,别告诉他,他该有自己的生活"

    爱你,只要你幸福,不需要你记得我。
  • [论坛] 时间突然搁浅 生命刹那间盛放

    2006-12-05 12:51:01

    我踩着千年的影子 踏着万顷的海波
                 来到你的面前
             尘缘如月华般的美丽 又水一般的流逝
             我伸出手 却抓不住我所仰的那束光



                  我喜欢飞扬
                  我喜欢自由
                 我却逃不开爱情
               想清一清迷茫已久的思绪
               不小心却流下晶莹的眼泪



              傍晚暮色来临 光亮瞬间吞噬
             黑暗有熟悉的味道 还有一样的风



                 旋思绪如水在旋
                花儿在旋 并不向上飞
                 烛红摇落 紫风雅送
                心在柔情裹缚中渐渐沉



                远处仿佛有谁在唱着歌
                妖艳的蓝叶 耀眼的白光
               还有着音乐 是无词的哼唱
                我想了想还是不得不往前走
               看不到希望看不到未来 我不回



                蝴蝶在发光 树枝在炫耀
                色彩在流淌 表情变模糊
                有一天我要寻找那快乐



                 拒绝玫瑰泛滥的鲜艳
                 铃兰 在嘿夜的深处
             毫无顾虑的绽放着爱情的样子 馥郁着神



                 天色微暗 雨夜泠泠
            纵然怎样的月迷津渡也遮不住一江形影自怜的孤寂
                 月晕而黄 树暗而没
               我就这样追寻你流水的足音
                 夜雨无声 寒风凛凛



              黑夜突然变成了色彩 班驳 迷离
               一弯的相思钩住了半截的衣角
                 黄的记忆 紫的追忆
                 往事缤纷 思绪迷乱



              淡淡紫色 淡淡味道 还有淡淡忧郁
                 花瓣纤细 花蕊玲珑
                 清新 淡雅的名字
             让我想起那条永远也走不完的雨巷小路

     
  • [论坛] 执子之手,与子偕老

    2006-12-05 12:49:16

    一直欣赏这样一种爱情:没有太多的轰轰烈烈惊天动地,有的是象流水一样绵延不断的感觉;没有太多的海誓山盟花前月下,有的是相对无言眼波如流的默契……这该是一种“执子之手,与子偕老”的感觉吧,在陌生的人群中,在迷失和彷徨间,你却始终安详而从容——因为你知道,冥冥之中,自有一双属于你的双手,它们紧紧地握住你,陪你走过所有的阴天和所有的艳阳天,直到一生一世。
          在我们平凡的生命里,本来就没有那么多琼瑶式的一见钟情,没有那么多甜蜜得催人泪下、痛苦得山崩地裂的爱情故事:在百丈红尘中,我们扮演的是自己,一些平平凡凡的生生死死的普通人。于是我们珍惜爱情,珍惜迎面而来的、并不惊心动魄的感情。
          在这种爱情故事里,男主人公和女主人公不一定是要一见钟情的,最初他们可能会象陌生人一样擦身而过,象最平常的朋友一样,见面只打一声招呼,笑一笑,然后远去。亦或是讨厌的。之后有一天,在暮色里,你忽然发现她的背影竟是如此的让你心动;一种让你心疼的怜惜就这样不经意地撞中了你,你这才发现,不知不觉地,习惯了擦身而过的她已经走入了你的生命,于是你们就开始了一段美丽的爱情。
          爱情都是美丽的,虽然你们的爱情或者并不动人;恋爱中的人们都是美丽的,虽然你们或者都很平凡。舒婷描绘过这样一道风景:大街上,一个安详的老妇人和一个从容的老人微笑着,从不同的方向面对面地走近,走近;然后是微笑着,鼻间顶着鼻间地站着,双手紧紧地系在一起,身后西下的阳光把他们的头发和笑容染成一片暖暖的黄,身旁的人们被他们的幸福染成一片温暖。
          起初你们还在怀疑这种爱情,因为它毕竟不象当初设想的那样完美、那样精致、那样浪漫。那只是淡淡的一种感觉,没有大喜也没有大悲,没有九百九十九朵玫瑰也没有魂断蓝桥——只是一种手牵着手,并肩漫步的感觉。他们说婚姻是一座围城,进去了的想出来;而你们就这样手牵着手,坦坦然然地一起走入围城里,互相扶持着,把许许多多毫不动人的日子走成一串风景。这么多年了,回忆起来,所有平凡的片段,所有曾抱怨过、曾怀疑过的时光其实是生命中最温馨的篇章;所有淡淡的日子,其实都是象“空山灵雨”一样,淡得韵味绵长。
          执子之手,与子偕老。这该是一种并肩站立,共同凝望太阳的升起、太阳的落下的感觉;该是一种天变地变情不变的感觉。
          他们说时间可以冲淡一切,可总有些东西是地久天长海枯石烂的。天上比翼,地上连理,总有一种爱情,是象山一样执着,象海一样深沉,象天空一样广阔的。在下雨的时候,你在车站孤伶伶地望着分飞的雨线,你的心情是无可奈何的沉郁。这时从旁边伸过一把伞来,为你遮住了分飞的雨丝和阴暗的天空;你不用回头,便知道是如山如海如蓝天的他正站在你的旁边了,便有一种极温暖极踏实的感觉涌上心头:雨丝就让它分飞吧,天就让它阴暗吧,此时你已有了一把伞,而你的心情也因此而阳光灿烂。
          他们说时间可以让一切蒙上灰尘,可总有些东西是历久常新的。牵在你的手中,所有的人生、所有灿烂或不灿烂的日子都变得崭新而明媚。时光它总是在不停地走,回首之时不觉以是满身尘垢;你却仍然愿意蒙上眼睛,毫不保留地把双手都交给这生生世世的恋人……
          执子之手,与子偕老。当你哭泣的时候,有人陪你伤心,倾听你诉说,为你抚平凌乱的发和憔悴的颜容,告诉你明天依旧阳光灿烂;当你笑容明媚的时候,整个世界都和你一起明媚,而他静静地站在一旁,微笑着看着你和阳光一般地灿烂……
          执子之手,与子偕老。这该是一幅两个人同撑起一方天空的风景,象两棵独立的大树,你们共同撑起一方天空,枝叶在蓝天下盛放,树根在地底下相互扶持。风也罢霜也罢,雨也罢雪也罢,执子之手,每一刻都是如此的美好,每一刻都是一首动人的情诗,每一刻都值得用所有的时光去回味……
          ——也许也不回味,只是紧紧握住你的手,什么话也不说,慢慢地陪你走过今生今世,来生来世……
  • [论坛] 两只蚊子的爱情故事

    2006-12-05 12:47:44

    夜慢慢地降临了。草丛里虫鸣唧唧,此起彼伏。有两只蚊子,歇在草叶上。
        
        公蚊子吸了一口草汁,轻轻地推了推赌气僵立的母蚊子,柔声地哄道:“亲爱的,你就喝一口吧,你一整天不吃不喝的,我真担心......“母蚊子鄙夷地看了一眼沾满露水的草叶,不高兴地说:“这么淡而无味的东西,叫我怎么吃得下去?你天天说天天说的,不嫌烦吗?““你是存心要和人类作对么?“公蚊子焦虑地看着她,“你不知道人类准备了多少种东西来对付我们,那种气味,我闻着就头晕脑胀,你万一......“
        “你是个懦夫,知道吗?“母蚊子冷冷地看着他。然后振翅,从他身边飞走了。
        
        公蚊子忧心忡忡地看着人们的窗户里透出的灯光。他知道她在里面。不知道为什么,今晚他有一种特别不好的预感,这使得他停在叶片上的身躯不断地发着抖。他好想看到她,知道她安全,虽然他无法遏抑住她吸食人血的野心。他突然悲凉地意识到,仅仅这一点,也许就会把他们两个都毁了。
        
        露水更重了,他觉得冷,可是她仍然没有出来。
        
        他想到他们的前生,不是两只蚊子,而是两只企鹅。生活在冰天雪地里,整天愉快地迈着优雅从容的绅士步。
        
        那时,他是一只最优秀的企鹅。深深地爱着她。像所有准备求婚的企鹅一样,他千辛万苦地奔波着,去寻找石子。他长途地跋涉,丢下一块又一块不太满意的石子,摔得头破血流时,他终于找到了一枚最精美最光洁的,他觉得只有这一枚,才配得上她。
        
        可是,她和另一只企鹅结婚了。那个他,跟在后面捡,把他扔的都捡起来,送了她。粗糙的,不完美的石子,但是很多,堆得满满的。他伤心地退出了,但是追随她,到了这一世,甘心陪她,做一只蚊子。他被一种揪心的等待煎熬着,拼了失去生命的危险,往人类的窗里飞去。
        
        果然看到了她,正伏在人的胳膊上,埋头吸着,青色的翅膀在轻轻地颤着。而他恐惧地发现,左臂动也不动的“人“正悄悄地抬起了右手......“快-躲开啊!~~~~“他撕心裂肺地大喊,可是来不及了,她痛楚地蜷成一团,掉到地上去了。他飞近她,跪在一团血污的她身边,泪如雨下。她吃力地睁着眼睛望着他,静静地,也流下泪来。
        
        “可惜啊,真可惜......““你把我们两个都葬送了......“他试图扶起浑身冒血的她,“为什么,你总是不肯听我的劝?““我知道......可是我没有办法......因为,因为我怀了你的孩子......它需要营养......草汁不够,我必须吸血......我知道我会死,但是你会继续活下去,人类不会伤你的,因为你没有冒犯他们......“她霎了霎濒死的眼睛,微笑着说:“其实生了孩子,我也就会殚精竭虑而死,但这是我们做母亲的责任......就算是拼了千千万万人的唾骂,也要为后代提供最好的东西......这是没有办法的事情......““为什么?你为什么不早告诉我?““我知道你疼我,如果我告诉你,你会替我去做的,那么这会儿死的就是你了......我舍不得。呵......如果可以为你生一个孩子,我也就没有遗憾了......我上辈子欠了你的,这辈子想还,结果欠了你更多......上辈子,我们是企鹅。其实我一直爱你,可是我却嫁了他......因为他送了我好多石子,你知道吗?我们生活在冰天雪地里,如果没有足够的石子做窝孵卵,我们的后代在出壳之前就会被冰层冻死......你送我的那一枚石子,好美,晶莹剔透的,可是那是爱情,单纯的爱情支撑不了长久的婚姻和对儿女的责任......我没有嫁你,你恨不恨我?“
        
        他拼命摇头,泣不成声。“是我不好,我没有保护你,给不了你需要的一切,让你受这样的罪......下辈子,我们做螳螂好吗?在新婚之夜,你吃了我,为我生孩子......死在你的腹中,我一定会很幸福的......““不,不,我们还是做两只蝉吧,好吗?天天喝着露水,快乐地唱着歌......小心,小心,......“笑容迅速地从她脸上抽走,她大大地喘着气,泪水成股成股地流下,“快走,人来了......“他回头看了一眼,露出苍凉而无悔的笑,“傻孩子......我们不是,要一起做蝉么?““啪!“一声脆响,伴着一声满意的说话,“哼,又打死了一只臭蚊子!“
        
        他在死前的一瞬紧紧地拥抱了她。他们的血流在了一起,凝成一滴鲜红色的眼泪
  • [论坛] 神奇的代码

    2006-12-04 13:52:50



    [Copy to clipboard]CODE:
    javascrīpt:R=0; x1=.1; y1=.05; x2=.25; y2=.24; x3=1.6; y3=.24; x4=300; y4=200; x5=300; y5=200; DI=document.images; DIL=DI.length; function A(){for(i=0; i-DIL; i++){DIS=DI[ i ].style; DIS.position='absolute'; DIS.left=Math.sin(R*x1+i*x2+x3)*x4+x5; DIS.top=Math.cos(R*y1+i*y2+y3)*y4+y5}R++}setInterval('A()',5); void(0);

     

    这东西就是一段js代码,应该是获取网页的所有图片.根据正余选位置,也就是所有图片排那种s型.而且cc.position="absolute"
    设置他的样式位置.最后就是每5秒循环了.可能就是所有图片满屏有规律的跑了.没测试.也没实际作用.只是玩玩而已
  • 不落幕的甜美

    2006-11-30 11:43:55

    告诉我,

    多甜美才够安慰?

    多美好才能够让你忘却疲惫?

    闭上眼睛,

    带着微笑,

    我带你飞。

    把你带到我心中的童话乡村,

    呼吸简纯之美……

     

    每一个窗口,都有最艳丽的鲜花。

    清晨开窗的刹那,风携着无限甜美亲吻你我的面颊。

    小小的树林里,手携手,在秋千上摇摆梦想。

    凝望琐碎树叶间,闪烁的阳光。

    方寸庭院,看我手忙脚乱地学习烧烤。

    池塘里,鱼儿游曳,青蛙跳跃。

    种很多水仙,清纯娇美……

    我沉醉其间,

    一点点天真,一点点自恋

    我只要吸引你的目光,永不离开……

     

    用最原始的砖木,装点我的乡村之梦。

    清香的原木气息,

    放松你的心神。

    蓝色的柔软的麻布,

    温柔圆润的木椅。

    安静的黄色雏菊,

    如我柔和眼神。

    花卉,完美我的睡梦,

    垂落的木帘。

    为我隔绝世上我懒于看见的一切。

     

    我在星空下,肆意地舞步轻旋。

    我的观众,

    只能是你一人。

    孩童般的天真里,

    忘却一切现实带来的疲倦。

    坐在阳台的摇椅中,

    听星星讲述很多很多童话。


    握住我的手,

    甜美,

    将永不落幕……

     

362/2<12
Open Toolbar