zoukankan      html  css  js  c++  java
  • 单元测试概括

    一、单元测试的目的

    验证代码与设计相符合(Code Inspection与Unit Test相结合)

    跟踪需求和设计的实现

    发现设计和需求中存在的错误

    发现编码过程中引入的错误

    对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

    二、单元测试的环境

    构造最小运行调度系统,即驱动模块(Driver),用以模拟被测模块的上一级模块 模拟实现单元接口桩(Stub),即被测单元需调用的其他单元函数的接口 模拟生成数据或状态,为单元测试准备动态环境

    三、单元测试的方法

    孤立测试策略 单元内的全局输入/输出变量测试(Driver) 单元内调用的函数(Stub)的接口测试 覆盖测试(语句覆盖/分支覆盖/复合谓词覆盖/路径覆盖)。 Note:应该依据规格说明书、流程图并结合源程序规划测试方法和测试用例。

    四、单元测试的测试用例设计

    为系统运行与正向测试设计测试用例:等价类划分、决策表 为逆向测试设计测试用例:边界值法 为代码覆盖设计测试用例:代码覆盖:语句覆盖、分支覆盖、复合谓词覆盖、路径覆盖、数据定义使用测试

    五、单元测试应坚持的原则

    单元测试前应该执行静态检查、代码走读 对全新的代码或修改过的代码进行单元测试 被测试的对象为实现一组相关功能的代码(一个或一组函数) 单元测试根据单元测试的计划和方案进行,排除测试的随意性 项目管理者保证测试用例经过审核(集思广益) 当测试用例的测试结果与预期结果不一致时,单元测试的执行人员需如实记录实际测试结果 当测试达到计划的结束标准时,单元测试结束 对被侧单元需达到一定的代码覆盖率要求 当程序修改后,测试人员要执行回归测试,以保证修改后没有引入新的错误。

    我们编写代码时,一定会反复调试保证它能够编译通过。如果是编译没有通过的代码,没有任何人会愿意交付给自己的老板。但代码通过编译,只是说明了它的语法正确;我们却无法保证它的语义也一定正确,没有任何人可以轻易承诺这段代码的行为一定是正确的。

    幸运的是,单元测试会为我们的承诺做保证。编写单元测试就是用来验证这段代码的行为是否与我们期望的一致。有了单元测试,我们可以自信的交付自己的代码,而没有任何的后顾之忧。

    什么时候测试?单元测试越早越好,早到什么程度?XP开发理论讲究TDD,即测试驱动开发,先编写测试代码,再进行开发。在实际的工作中,可以不必过分强调先什么后什么,重要的是高效和感觉舒适。从老纳的经验来看,先编写产品函数的框架,然后编写测试函数,针对产品函数的功能编写测试用例,然后编写产品函数的代码,每写一个功能点都运行测试,随时补充测试用例。所谓先编写产品函数的框架,是指先编写函数空的实现,有返回值的随便返回一个值,编译通过后再编写测试代码,这时,函数名、参数表、返回类型都应该确定下来了,所编写的测试代码以后需修改的可能性比较小。

    由谁测试?单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成,也就是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门可以作一定程度的审核。

    关于桩代码,老纳认为,单元测试应避免编写桩代码。桩代码就是用来代替某些代码的代码,例如,产品函数或测试函数调用了一个未编写的函数,可以编写桩函数来代替该被调用的函数,桩代码也用于实现测试隔离。采用由底向上的方式进行开发,底层的代码先开发并先测试,可以避免编写桩代码,这样做的好处有:减少了工作量;测试上层函数时,也是对下层函数的间接测试;当下层函数修改时,通过回归测试可以确认修改是否导致上层函数产生错误。

    在一种传统的结构化编程语言中,比如C,要进行测试的单元一般是函数或子过程。在象C++这样的面向对象的语言中, 要进行测试的基本单元是类。对Ada语言来说,开发人员可以选择是在独立的过程和函数,还是在Ada包的级别上进行单元测试。单元测试的原则同样被扩展到第四代语言(4GL)的开发中,在这里基本单元被典型地划分为一个菜单或显示界面。

    六、单元测试工具

    代码静态分析工具:Logiscope、McCabe QA、CodeTest 代码检查工具:PC-LINT、CodeChk、Logiscope 测试脚本工具:TCL、Python、Perl 覆盖率检测工具: Visual studio ,Logiscope、Purecoverage 内存检测工具:Purify、CodeTest 单元测试工具:Visual studio 2005-2013,xUnit

    七、实验内容

    创建解决方案和单元测试项目

    在“文件”菜单上选择“新建”,然后选择“新建项目”。 

    在“新建项目”对话框中,展开“已安装”、“Visual C#,选择“Windows Store。  然后从项目模板列表中选择“空白应用程序”。

    将项目命名为 Maths,并确保选中“创建解决方案的目录”。 

    在解决方案资源管理器中,选择解决方案名称,从快捷菜单中选择“添加”,然后选择“新建项目”。 

    在“新建项目”对话框中,展开“已安装”、“Visual C#,然后选择“Windows 应用商店”。  然后从项目模板列表中选择“单元测试库(Windows Store 应用程序)

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;

     

    namespace UnitTestLibrary1

    {

        [TestClass]

        public class UnitTest1

        {

            [TestMethod]

            public void TestMethod1()

            {

                Assert.AreEqual(0, 0);

     

    }

     

            }

        }

    以下是测试源码

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Threading.Tasks;

     

    namespace App1

    {

        public class Class1

        {

            public Class1()

        {

        }

            public double SquareRoot(double x)

            {

                double estimate = x;

                double diff = x;

                if (x < 0.0)

                {

                    throw new ArgumentOutOfRangeException();

                }

     

                while (diff > estimate / 1000)

                {

                    double previousEstimate = estimate;

                    estimate = estimate - (estimate * estimate - x) / (2 * estimate);

                    diff = Math.Abs(previousEstimate - estimate);

                }

                return estimate;

     

            }

     

     

        }

    }

     

     

     

     

     

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;

    using App1;

     

    namespace UnitTestLibrary1

    {

        [TestClass]

        public class UnitTest1

        {

            [TestMethod]

            public void TestMethod1()

            {

                Assert.AreEqual(0, 0);

     

            }

             [TestMethod]

            public void BasicTest()

            {

                App1.Class1 rooter = new Class1();

                double expected = 0.0;

                double actual = rooter.SquareRoot(expected * expected);

                double tolerance = .001;

                Assert.AreEqual(expected, actual, tolerance);

            }

            [TestMethod]

            public void RangeTest()

            {

                Class1 rooter = new Class1();

                for (double v = 1e-6; v < 1e6; v = v * 3.2)

                {

                    double expected = v;

                    double actual = rooter.SquareRoot(v * v);

                    double tolerance = expected;

                    Assert.AreEqual(expected, actual, tolerance);

                }

            }

            [TestMethod]

            public void NegativeRangeTest()

            {

                string message;

                Class1 rooter = new Class1();

                for (double v = -0.1; v > -3.0; v = v - 0.5)

                {

                    try

                    {

                        // Should raise an exception:

                        double actual = rooter.SquareRoot(v);

     

                        message = String.Format("No exception for input {0}", v);

                        Assert.Fail(message);

                    }

                    catch (ArgumentOutOfRangeException ex)

                    {

                        continue; // Correct exception.

                    }

                    catch (Exception e)

                    {

                        message = String.Format("Incorrect exception for {0}", v);

                        Assert.Fail(message);

                    }

                }

            }

     

     

     

     

            }

        }

     

     

     

    以下是app源码

    using System;

    using System.Collections.Generic;

    using System.IO;

    using System.Linq;

    using System.Runtime.InteropServices.WindowsRuntime;

    using Windows.ApplicationModel;

    using Windows.ApplicationModel.Activation;

    using Windows.Foundation;

    using Windows.Foundation.Collections;

    using Windows.UI.Xaml;

    using Windows.UI.Xaml.Controls;

    using Windows.UI.Xaml.Controls.Primitives;

    using Windows.UI.Xaml.Data;

    using Windows.UI.Xaml.Input;

    using Windows.UI.Xaml.Media;

    using Windows.UI.Xaml.Navigation;

     

    // “空白应用程序”模板在 http://go.microsoft.com/fwlink/?LinkId=234227 上有介绍

     

    namespace App1

    {

        /// <summary>

        /// 提供特定于应用程序的行为,以补充默认的应用程序类。

        /// </summary>

        sealed partial class App : Application

        {

            /// <summary>

            /// 初始化单一实例应用程序对象。    这是执行的创作代码的第一行,

            /// 逻辑上等同于 main() 或 WinMain()。

            /// </summary>

            public App()

            {

                this.InitializeComponent();

                this.Suspending += OnSuspending;

            }

     

            /// <summary>

            /// 在应用程序由最终用户正常启动时进行调用。

            /// 以打开特定文件等情况下使用其他入口点。

            /// </summary>

            /// <param name="e">有关启动请求和过程的详细信息。</param>

            protected override void OnLaunched(LaunchActivatedEventArgs e)

            {

     

    #if DEBUG

                if (System.Diagnostics.Debugger.IsAttached)

                {

                    this.DebugSettings.EnableFrameRateCounter = true;

                }

    #endif

     

                Frame rootFrame = Window.Current.Content as Frame;

     

                // 不要在窗口已包含内容时重复应用程序初始化,

                // 只需确保窗口处于活动状态

                if (rootFrame == null)

                {

                    // 创建要充当导航上下文的框架,并导航到第一页

                    rootFrame = new Frame();

                    //设置默认语言

                    rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];

     

                    rootFrame.NavigationFailed += OnNavigationFailed;

     

                    if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)

                    {

                        //TODO:  从之前挂起的应用程序加载状态

                    }

     

                    // 将框架放在当前窗口中

                    Window.Current.Content = rootFrame;

                }

     

                if (rootFrame.Content == null)

                {

                    // 当未还原导航堆栈时,导航到第一页,

                    // 并通过将所需信息作为导航参数传入来配置

                    // 参数

                    rootFrame.Navigate(typeof(MainPage), e.Arguments);

                }

                // 确保当前窗口处于活动状态

                Window.Current.Activate();

            }

     

            /// <summary>

            ///导航到特定页失败时调用

            /// </summary>

            ///<param name="sender">导航失败的框架</param>

            ///<param name="e">有关导航失败的详细信息</param>

            void OnNavigationFailed(object sender, NavigationFailedEventArgs e)

            {

                throw new Exception("Failed to load Page " + e.SourcePageType.FullName);

            }

     

            /// <summary>

            /// 在将要挂起应用程序执行时调用。    在不知道应用程序

            /// 将被终止还是恢复的情况下保存应用程序状态,

            /// 并让内存内容保持不变。

            /// </summary>

            /// <param name="sender">挂起的请求的源。</param>

            /// <param name="e">有关挂起的请求的详细信息。</param>

            private void OnSuspending(object sender, SuspendingEventArgs e)

            {

                var deferral = e.SuspendingOperation.GetDeferral();

                //TODO:  保存应用程序状态并停止任何后台活动

                deferral.Complete();

            }

        }

    }

     

     

     

  • 相关阅读:
    bzoj2959
    学习笔记::lct
    bzoj3203
    bzoj1319
    bzoj3625
    bzoj3992
    bzoj1565
    bzoj3513
    平常练习动归(1.胖男孩)———最长公共子序列
    2016 noip 复赛 day2
  • 原文地址:https://www.cnblogs.com/2522150225qq/p/4475034.html
Copyright © 2011-2022 走看看