• [Test] 单元测试艺术(1) 基础知识


    单元测试不是软件开发的新概念,在1970年就一直存在,屡屡被证明是最理想的方法之一。

    本系列将分成3节:

    1. 单元测试基础知识
    2. 打破依赖,使用模拟对象,桩对象,测试框架
    3. 创建优秀的单元测试

    本节索引:

    单元测试与集成测试

    单元测试几乎总是基于框架来写的,因为框架可以为我们提供统一的API来管理测试。

    常用的框架有Unit Test(MS Test),NUnit(开源)

    定义

    单元测试是一段代码调用另一段代码,随后检验一些假设的正确性。(单元指的是一个方法或函数)

    集成测试是指把2个或多个互相依赖的软件模块作为一组进行测试。

    优秀的单元测试准则

    1. 自动的,可重复
    2. 容易实现
    3. 持续可用
    4. 简单
    5. 快速

    测试驱动(TDD)开发

    对于TDD确切的含义,有很多不同的观点,有人觉得就是测试优先的开发,有人觉得意味着大量的测试,有人觉得是一种设计方法。

    TDD的流程:

    写测试 写代码 重构 写下一个测试

    它显示了TDD是增量性质的,每次一小步,最终完成高质量的软件。(重构可以在完成每个测试后进行,也可以在完成几个测试后进行。重构是非常有价值意义的。)

    TDD的优点:

    1. 较高的代码测试覆盖率
    2. 测试是可信赖的
    3. 辅助设计,减少代码复杂度

    MS Test和NUnit

    所有的测试框架都共享相同的核心特性:Test Declaration, Test Execution, and Assertions.

    在.Net中一般使用特性标签来添加额外的信息,下面就是MS Test和NUnit在特性标签上不同的地方。

    MS Test Attribute NUnit Attribute 用途
    [TestClass] [TestFixture] 定义一个测试类,里面可以包含很多测试函数和初始化、销毁函数(以下所有标签和其他断言)。
    [TestMethod] [Test] 定义一个独立的测试函数。
    [ClassInitialize] [TestFixtureSetUp] 定义一个测试类初始化函数,每当运行测试类中的一个或多个测试函数时,这个函数将会在测试函数被调用前被调用一次(在第一个测试函数运行前会被调用)。
    [ClassCleanup] [TestFixtureTearDown] 定义一个测试类销毁函数,每当测试类中的选中的测试函数全部运行结束后运行(在最后一个测试函数运行结束后运行)。
    [TestInitialize] [SetUp] 定义测试函数初始化函数,每个测试函数运行前都会被调用一次。
    [TestCleanup] [TearDown] 定义测试函数销毁函数,每个测试函数执行完后都会被调用一次。
    [AssemblyInitialize] -- 定义测试Assembly初始化函数,每当这个Assembly中的有测试函数被运行前,会被调用一次(在Assembly中第一个测试函数运行前会被调用)。
    [AssemblyCleanup] -- 定义测试Assembly销毁函数,当Assembly中所有测试函数运行结束后,运行一次。(在Assembly中所有测试函数运行结束后被调用)
    [DescriptionAttribute] [Category] 定义标识分组。

    第一个单元测试

    安装

    对于MS Test,只要安装VS则会自动安装。在工具栏==测试==窗口==测试资源管理器打开。

    对于NUnit,点击链接,下载安装即可。

    编码

    1. 配置对象
    2. 操作对象
    3. 断言结果
    [TestClass]
        public class BlogTests
        {
            public DbContext Db { get; set; }
    
            /// <summary>
            /// 每个测试方法执行前都会执行
            /// </summary>
            [TestInitialize]
            public void Init()
            {
                //1 配置对象
                Db = new DbContext();
            }
    
            [TestMethod]
            public void TestAdd()
            {
                var blog = new Blog { Title = "单元测试的艺术", Content = "单元测试是一门艺术" };
                //2 操作对象
                Db.Add(blog);
                //3 断言结果
                Assert.IsTrue(blog.Id > 0);
            }
            
            /// <summary>
            /// 每个测试方法执行后都会执行
            /// </summary>
            [TestCleanup]
            public void Clean()
            {
                Db = null;
            }
        }

    异常的测试

    有时候,测试里面上需要抛出异常,这是业务上的正确性。在单元测试里,也有对应特性用来实现。如

    [ExpectedException(typeof(OutOfMemoryException), AllowDerivedTypes = true)]//默认异常的子类也会不通过测试的
            [TestMethod]
            public void TestAdd()
            {
                var blog = new Blog { Title = "单元测试的艺术", Content = "单元测试是一门艺术" };
                //2 操作对象
                Db.Add(blog);
                throw new OutOfMemoryException();
                //3 断言结果
                Assert.IsTrue(blog.Id > 0);
            }

    忽略的测试

    有时候,测试写的有问题,代码没问题。我们可以暂时忽略该测试

            [Ignore]
            [TestMethod]
            public void TestAdd()
            {
                var blog = new Blog { Title = "单元测试的艺术", Content = "单元测试是一门艺术" };
                //2 操作对象
                Db.Add(blog);
                throw new OutOfMemoryException();
                //3 断言结果
                Assert.IsTrue(blog.Id > 0);
            }

    对测试分组

    当我们只想测试某一类测试的时候,也有对应的特性

            [TestCategory("change db")]
            [TestMethod]
            public void TestAdd()
            {
                var blog = new Blog { Title = "单元测试的艺术", Content = "单元测试是一门艺术" };
                //2 操作对象
                Db.Add(blog);
                //3 断言结果
                Assert.IsTrue(blog.Id > 0);
            }
    
            [TestCategory("no change")]
            [TestMethod]
            public void TestRead()
            {
                //2 操作对象
                var blogs = Db.GetBlogs();
                //3 断言结果
                Assert.IsTrue(blogs.Length > 0);
            }

    运行选定的测试即可

    测试

     

    命名规范

    SUT Kind SUT
    项目 新建一个【被测项目】.Tests的测试项目
    至少为每个被测试类新建一个【被测类名】Tests的类
    方法

    至少为每个方法名新建一个【方法名】【测试场景】【预期行为】的方法

    或者使用Test【方法名】的简单命名

    备注:SUT("system under test")代表被测系统,有些人喜欢CUT("code under test")。通常SUT。

    本文作者:Never、C

    本文链接:http://www.cnblogs.com/neverc/p/4742654.html

  • 相关阅读:
    设置nginx中文件上传的大小限制度
    百度编辑器(ueditor)踩坑,图片转存无法使用
    帝国cms更换Ueditor编辑器上传图片加水印
    帝国cms7.5整合百度编辑器ueditor教程
    帝国CMS万能标签ecmsinfo介绍
    帝国CMS排行榜调用标签
    通过案例理解position:relative和position:absolute
    帝国CMS万能标签标题截取后自动加入省略号
    linux 安装字体
    Ecms7.5版CK编辑器保留word格式如何修改
  • 原文地址:https://www.cnblogs.com/neverc/p/4742654.html
Copyright © 2020-2023  润新知