Danny's profile季节的水滴PhotosBlogListsMore Tools Help

Blog


    9/23/2009

    抱住单元测试不放(转载)

    一般来说,SaaS 的领跑者往往是许多人构建的大型应用程序。大型应用程序的单元测试中,数据总是一致的:在后期执行单元测试的项目总是惨败。与此相反,成功的 SaaS 开发人员在编写代码之前运行单元测试。例如,如果我要编写一个名为ServiceController 的类,我不会直接开始编写该类。相反,我编写根据类中的方法运行所有单元测试用例的类。接下来我甚至会进一步运行测试用例,尽管我知道它们将失败,因为我没有为该类编写任务代码。

    这样做的目的在于,排除单元测试中出现 bug 的可能性,保证总是能通过单元测试。一般来说,很容易无意中犯这个错误。如果所有单元测试都失败,我就可以开始编写实际代码了。当我完成新类的编写时,我将再次运行单元测试。只要通过所有的测试用例,我就将向单元测试自动库添加新的单元测试类,在每次构建时运行。换句话说,我为应用程序创建的整个单元测试库都成为构建流程的一部分。实际上,在我每次开始构建项目之前,都将运行所有的单元测试,以确保应用程序代码的完整性没遭到无意破坏。

    在编程的世界中,我发现只有几个开发人员严格遵守该过程。但是,他们都是行业内最受尊敬的、最具声望、身价最高的开发人员。如果您想知道提高身价的捷径,请坚持单元测试。

    6/3/2009

    50 Specific Ways to Improve Your Testing

    1.  Requirements Phase
    Item 1: Involve Testers from the Beginning
    Item 2: Verify the Requirements
    Item 3: Design Test Procedures As Soon As Requirements Are Available
    Item 4: Ensure That Requirement Changes Are Communicated
    Item 5: Beware of Developing and Testing Based on an Existing System

    2.  Test Planning

    Item 6: Understand the Task At Hand and the Related Testing Goal
    Item 7: Consider the Risks
    Item 8: Base Testing Efforts on a Prioritized Feature Schedule
    Item 9: Keep Software Issues in Mind
    Item 10: Acquire Effective Test Data
    Item 11: Plan the Test Environment
    Item 12: Estimate Test Preparation and Execution Time

    3.  The Testing Team

    Item 13: Define Roles and Responsibilities
    Item 14: Require a Mixture of Testing Skills, Subject-Matter Expertise, and Experience
    Item 15: Evaluate the Tester's Effectiveness

    4.  The System Architecture

    Item 16: Understand the Architecture and Underlying Components
    Item 17: Verify That the System Supports Testability
    Item 18: Use Logging to Increase System Testability
    Item 19: Verify That the System Supports Debug and Release Execution Modes

    5.  Test Design and Documentation

    Item 20: Divide and Conquer
    Item 21: Mandate the Use of a Test-Procedure Template and Other Test-Design Standards
    Item 22: Derive Effective Test Cases from Requirements
    Item 23: Treat Test Procedures As "Living" Documents
    Item 24: Utilize System Design and Prototypes
    Item 25: Use Proven Testing Techniques when Designing Test-Case Scenarios
    Item 26: Avoid Including Constraints and Detailed Data Elements within Test Procedures
    Item 27: Apply Exploratory Testing

    6.  Unit Testing

    Item 28: Structure the Development Approach to Support Effective Unit Testing
    Item 29: Develop Unit Tests in Parallel or Before the Implementation
    Item 30: Make Unit-Test Execution Part of the Build Process

    7.  Automated Testing Tools

    Item 31: Know the Different Types of Testing-Support Tools
    Item 32: Consider Building a Tool Instead of Buying One
    Item 33: Know the Impact of Automated Tools on the Testing Effort
    Item 34: Focus on the Needs of Your Organization
    Item 35: Test the Tools on an Application Prototype

    8.  Automated Testing: Selected Best Practices

    Item 36: Do Not Rely Solely on Capture/Playback
    Item 37: Develop a Test Harness When Necessary
    Item 38: Use Proven Test-Script Development Techniques
    Item 39: Automate Regression Tests When Feasible
    Item 40: Implement Automated Builds and Smoke Tests

    9.  Nonfunctional Testing

    Item 41: Do Not Make Nonfunctional Testing an Afterthought
    Item 42: Conduct Performance Testing with Production-Sized Databases
    Item 43: Tailor Usability Tests to the Intended Audience
    Item 44: Consider All Aspects of Security, for Specific Requirements and System-Wide
    Item 45: Investigate the System's Implementation To Plan for Concurrency Tests
    Item 46: Set Up an Efficient Environment for Compatibility Testing

    10.  Managing Test Execution
    Item 47: Clearly Define the Beginning and End of the Test-Execution Cycle
    Item 48: Isolate the Test Environment from the Development Environment
    Item 49: Implement a Defect-Tracking Life Cycle
    Item 50: Track the Execution of the Testing Program
     

    Effective Software Testing: 50 Specific Ways to Improve Your Testing

    By Elfriede Dustin

    Publisher: Addison Wesley

    Pub Date: December 18, 2002

    ISBN: 0-201-79429-2

    1/18/2009

    ADO.NET测试(二) --测试有返回值的存储过程

         假如,我们要测试一个叫做usp_MoreThan()的存储过程,这个存储过程返回SQL表中价格高于输入数值的int值:
    create procedure usp_MoreThan
        @inputPrice money
    as
        declare @ans int
        select @ans = count(*) from tblPrices where price > inputPrice
        return @ans
    go
    1. int expected = 2;
    2. int actual;
    3. string input = "100.00";
    4. string connString = "Server=(local);Database=dbPrices;UID=userId;PWD=password";
    5. SqlConnection sc = new SqlConnection(connString);
    6. SqlCommend cmd = new SqlCommend("usp_MoreThan", sc);
    7. cmd.CommandType = CommandType.StoredProcedure;
    8. SqlParameter p1 = cmd.Parameters.Add("ret_val", SqlDbType.Int);
    9. p1.Direction = ParameterDirection.ReturnValue;
    10. SqlParameter p2 = cmd.Parameters.Add("@inputPrice", SqlDbType.Money);
    11. p2.Direction = ParameterDirection.Input;
    12. p2.Value = input;
    13. sc.open();
    14. if(actual == expected)
    15.     Console.WriteLine("Pass");
    16. else
    17.     Console.WriteLine("Fail");
    1/7/2009

    ADO.NET测试(一) --当期望值是DataSet时

    设有一个用户信息的SQL表,表中有Iddescription两项。待测系统适用一个SqlDataAdapter对象从这个表里把数据读取到一个DataSet对象。

     

    假如对于一个特定的测试用例输入,期望的DataSet包含下面3项数据:                                      

    001

    Widget

    002

    Wadget

    003

    Wodget

    那么期望的聚合字符串就应该是:001Widget002Wadget003Wodget

     

    可以通过下面代码检查实际的DataSet对象是否包含期望的数据项:

    1.             string ds = new DataSet(); //把实际结果保存到DataSet ds

    2.              

    3.             string expectData = "001Widget002Wadget003Wodget";

    4.             string actualData = null;

    5.              

    6.             DataTable dt = ds.Tables[0];

    7.             foreach(DataRow de in dt.Rows)

    8.             {

    9.                 foreach(DataColumn dc in dt.Columns)

    10.             {

    11.                 actualData += dr[dc];

    12.             }

    13.         }

    14.          

    15.         if(actualData == expectData)

    16.             Console.WriteLine("Pass");

    17.         else

    18.             Console.WriteLine("Fail");

    我们应该首先取回实际DataSet对象里的DataTable对象,然后遍历它的DataRow集合,获得每个列的值,并且把它追加到字符串变量的后面。

     

    如果期望数据非常多,我们可以通过计算并比较这些数据的哈希值即可:

    1.             string ds = new DataSet();

    2.              

    3.             //string expectedData = "001Widget002Wadget003Wodget";

    4.             string expectedHash = "EC-5C-E5-E5-6D-1D-8C-DD-6E-2A-2B-6B-D3-CB-C1-28"

    5.             string actualData = null;

    6.             string actualHash = null;

    7.              

    8.             DataTable dt = ds.Tables[0];

    9.             foreach(DataRow de in dt.Rows)

    10.         {

    11.             foreach(DataColumn dc in dt.Columns)

    12.             {

    13.                 actualData += dr[dc];

    14.             }

    15.         }

    16.          

    17.         MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

    18.         byte[] ba = md5.ComputeHash(Encodeing.ASCII.GetBytes(actualData));

    19.         actualHash = BitConverter.ToString(ba);  //返回一个用连字符号(-)连接的表示16进制数的字符串

    20.          

    21.         if(actualHash == expectedHash)

    22.             Console.WriteLine("Pass");

    23.         else

    24.             Console.WriteLine("Fail");

    通过比较期望值数据的MD5(Message Digest version 5)哈希值,可以避免存储非常多的期望字符串数据,因为所有MD5哈希值的长度都是16个字节。用于加密的哈希算法(和用于哈希表的哈希算法不同),其目的是为了产生一个字节序列的指纹,或者说摘要。因为哈希的过程是不可逆的,这些哈希值仅仅用于识别,而不是加密/揭秘。