【C#编程最佳实践 一】单元测试实践

简介: 【C#编程最佳实践 一】单元测试实践

工作三周了,深深理解了学校和工作中处理问题的不同,从武哥这里得到了四字经验:最佳实践,而这个最佳实践是先投入工作,而后获取结论,改变之前先理论后实践的做法。于是产生了写一系列的博文的想法,积累工作中的经验,希望以后少踩坑,本篇为开篇第一篇,涉及到我这两周真正有所实践的学习–单元测试。本系列最佳实践每一篇博文都长期更新,而且每一篇都会分两方面来讲:1,知识的通用性,2,知识在工作中的最佳实践。

单元测试

注意:本篇只针对C#,适用版本vs2015

定义

是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,Java里单元指一个类,C#中,一个方法,一个类,一个窗口的测试。即单元测试。单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中 要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

一些常识

测试范围:单元测试一般针对公共方法,例如public修饰的方法

测试人:编写者自身

测试时机:在函数编写之前,并随着功能增加不断增加测试用例

通用操作

创建和运行

1,创建单元测试项目

2,依据要测试的项目,各级对应创建相应的文件夹

3,在文件夹下添加单元测试

4,注意待测方法前要加[Test Method],否则不能生成单元测试

5,第一次测试的时候要生成解决方案,然后才能运行或调试单元测试

常用测试方法

常用测试方法测试:

Assert.IsNull() 测试指定的对象是否为空引用,如果为空,则测试通过;

Assert.IsNotNull() 测试指定的对象是否为非空,如果不为空,则测试通过;

Assert.IsTrue() 测试指定的条件是否为True,如果为True,则测试通过;

Assert.AreEqual() 测试指定的值是否相等,如果相等,则测试通过;

对于不同返回类型需要做哪些测试

**对于int型:**Assert.AreEqual()方法来测试是否和预期值相等,一般测试是否为1

对于String类型的:先测是否为null---Assert.IsNull(),然后测是否为空串Assert.AreEqual(),最后测和预期值是否相符Assert.AreEqual()

对于list类型:先测是否为null–Assert.IsNull(),然后测list.Count>0是否为真Assert.IsTrue() ,最后测返回列表个数list.Count是否和预期相同Assert.AreEqual()

最佳实践

随着单元测试的深入,持续进行,会涉及到各个方面:首先,DAO层的单元测试最佳实践

最佳实践规则

1,单元测试原子性,没有switch,没有分支,总体来说,圈复杂度为1–ps(vs2015可安装CodeMetrics插件检测圈复杂度)

2,单一职责,指行为不是方法,类例如数据库里的增删改查,CRU和SafeCRU,一个整体行为,而不是多个方法,这样可以减少代码量,而且也对整个行为进行了测试

3,独立无耦合,单元测试间不能相互调用,否则有可能出现无限循环错误

4,属性值不共享,每个独立单元都要准备自己的数据,虽然复用低,但是能保证一致

5,测试驱动开发,单元测试越早越好,我之后写代码也要记住这一点

最佳实践结构

依照个人经验总结以下结构:

1,测试类内准备的公共数据

该测试准备数据修饰为private static

1,公共待测数据:公有的,各个方法都会使用到的测试数据

2,公共的预期值:公有的,约定好的各个待测方法的执行预期值

2,测试类内准备的继承自父类方法的测试

由于一些类可能会共用一些方法,所以可以抽象出一个公共父类,这样我们把所有公共父类所有的方法单独拿出来测试,这样每一个子类测试的时候测试到公有父类的方法可以减少错误的发生,甚至可以直接copy代码

该测试方法修饰为 public void 待测方法名()注意,一定要为public,否则测试无法进行

1,该方法私有的待测数据:私有的,该方法测试需要用到的数据 类型一般为var

2,该方法私有的业务测试:私有的,该方法核心功能的测试(例如一个更新操作函数,就不需要对其它诸如创建等做过多assert)

3,销毁为测试准备的所有数据(公有+私有)

3,测试类内准备的自身实现的方法的测试

不是从父类继承的公用方法,也主要包括三个步骤

该测试方法修饰为 public void 待测方法名()注意,一定要为public,否则测试无法进行

1,该方法私有的待测数据:私有的,该方法测试需要用到的数据 类型一般为var

2,该方法私有的业务测试:私有的,该方法核心功能的测试(例如一个更新操作函数,就不需要对其它诸如创建等做过多assert)

3,销毁为测试准备的所有数据(公有+私有)

最佳实践操作

tip:还可以做代码覆盖率检测哦。利用vs自带的代码覆盖率检测可以看到有哪些方法还没有被测试

DAO层进行的最佳实践

dao层一般用于和数据库的存储过程进行交互,操作无外乎增删改查,且大多数的增删都是通过id来操作,而更新和删除则是通过id和一些相应的参数来实现。

公有的准备数据

对应于准备数据的最佳实践:一般先不做公共准备数据,而是先写各个方法自己存在的准备数据,最后发现统一的可以抽象成公共数据。经过实践,我们可以这么准备数据

#region 公共的准备数据
        // *************************************************************公共的准备数据
        private static int age= 2345;   //例如下边的方法用到了age,所以抽象出来
        /// <summary>
        /// 创建方法,如果每个测试方法都用到了Create,则把它抽象出来实现复用(但不能再将其视为单元测试方法)
        /// </summary>
        /// <returns></returns>
        private int Create(Guid id)
        {
            var model = Build(id);
            return UserDao.Instance.Create(model);
        }
        /// <summary>
        /// 实例构造方法
        /// </summary>
        /// <returns></returns>
        private User Build(Guid id)
        {
            return new User()
            {
                ID = id,
                UserName = "tianmaolin",
                Age=age
             };
        }
        #endregion 公共的准备数据
        #region 公共的预期值
        //*************************************************************公共的预期参数值
        private static int checkDataRight = 1;
        #endregion 公共的预期值

对方法进行单元测试

#region 继承自父类的方法进行的单元测试
        //********************继承自父类的方法进行的单元测试***********************************
        /// <summary>
        /// 基于id测试用户的增删改查
        /// <param name="id"/>
        /// </summary>
        [TestMethod]
        public void UserCRUD()
        {
            //准备数据==========================================================SetUp
            var id = Guid.NewGuid();
            var model = Build(id);
            var create = Create(id);
            //准备好的更新状态
            var modelupdate = new User()
            {
                ID = id,
                UserName = "tttttttt",
            };
            //测试创建============================================================ C
            //测试是否创建成功
            Assert.AreEqual(checkDataRight, create);
            //测试是否查询成功=====================================================R
            var read = UserDao.Instance.GetById(id);
            Assert.IsNotNull(read);  //非空测试
            Assert.IsTrue(read.ID == id);//Guid一致性测试
            Assert.IsTrue(read.UserName == "tianmaolin");//创建者姓名一致    
            Assert.IsTrue(read.Age == age);//创建者年龄一致性测试
            //测试是否更新成功(依据新model更新) =================================== U
            var update = UserDao.Instance.Update(modelupdate);
            Assert.AreEqual(checkDataRight, update);//更新成功测试
            var readupdate = UserDao.Instance.GetById(id);//更新后获取
            Assert.IsTrue(read.UserName == "tttttttt"),创建者姓名更新测试      
            //测试删除=============================================================D
            var delete = UserDao.Instance.Delete(id);
            Assert.AreEqual(checkDataRight, delete);//是否删除成功
            var readagain = UserDao.Instance.GetById(id);//再次查询
            Assert.IsNull(readagain);//为空则删除成功
            //====================================================================TearDown
        }
        #endregion 继承自父类的方法进行的单元测试

踩过的坑

1,如果两张表有主外键关联关系,对从表的数据进行单元测试的时候先要创建主表的数据,最后还要记得销毁主表里的数据,例如student的插入依赖class。

2,写单元测试之前,一定要看代码的具体实现,我写代码发现存储过程里的操作之前有查重操作,然而自己并没有看好,导致每次都插入失败,血淋淋的教训,一定要先看好待测函数的功能实现,避免采坑!!!,尤其是涉及到模糊查询的时候,创建第二条数据的时候一定要改变要求非重复的值,否则会创建失败。

3,涉及到更新的单元测试,提前准备好更新数据,还得注意哪些数据无需更新,不是所有传入的参数都是要更新的,不要导致一直报错

建议测试过程

1,先看函数要实现什么功能,一定要理解他要的输入和期望的输出,如果有分支流程还得注意准备两套数据,如果有更新要提前准备更新数据

2,再看存储过程需要什么参数,存储过程里是否有查重等条件限定,要创建满足条件限定的准备数据

3,然后要准备好数据,发现多个方法有公有数据,统一拿出来,创建这种通用操作抽离出来

4,测试之后一定要记得销毁数据

5,出错要耐心调试,注意表间关系

相关文章
|
7天前
|
机器学习/深度学习 敏捷开发 人工智能
探索自动化测试的前沿技术与实践挑战
【7月更文挑战第8天】随着信息技术的飞速发展,软件测试领域正经历着前所未有的变革。自动化测试作为提升测试效率、确保软件质量的重要手段,其前沿技术与实践挑战备受关注。本文深入探讨了自动化测试的最新进展,包括人工智能在测试用例生成中的应用、持续集成/持续部署(CI/CD)流程中的自动化策略、以及云测试平台的兴起。同时,文章分析了自动化测试实施过程中遇到的主要挑战,如环境配置的复杂性、测试用例的维护问题和跨平台测试的困难,并提供了相应的解决策略。通过案例分析,展示了成功实施自动化测试的关键因素,为软件测试专业人员提供了宝贵的参考和启示。
21 2
|
1天前
|
敏捷开发 测试技术 持续交付
探索自动化测试框架的演进与实践
【7月更文挑战第14天】自动化测试框架在软件开发生命周期中扮演着越来越重要的角色。本文旨在探讨自动化测试框架从简单的脚本到复杂的系统级解决方案的演变过程,并分析其在不同阶段解决的关键问题。通过案例研究,我们将深入了解如何选择合适的自动化测试工具以及设计有效的测试策略,以提升软件质量保障的效率和效果。
|
2天前
|
敏捷开发 存储 数据管理
自动化测试框架设计:从理论到实践
【7月更文挑战第13天】本文将深入探讨自动化测试框架的设计原理与实现方法。通过分析自动化测试的必要性和框架设计的基本原则,结合具体案例,展示如何从零开始构建一个高效、可维护的自动化测试系统。文章不仅涵盖框架的结构设计,还包括最佳实践和常见问题的解决策略,为读者提供一套完整的解决方案和实操指南。
|
3天前
|
敏捷开发 机器学习/深度学习 人工智能
探索式测试在现代软件工程中的实践与挑战
随着软件开发模式的迭代升级,传统的测试方法已不能完全满足快速变化的市场需求和敏捷开发的节奏。探索式测试作为一种灵活、启发式的测试实践,逐渐受到业界的关注。本文将深入探讨探索式测试的定义、特点及其在现代软件工程中的应用,并分析实施过程中可能遇到的挑战,旨在为软件测试人员提供一种创新的测试视角和方法。
|
7天前
|
JavaScript 前端开发 测试技术
自动化测试在API测试中的深度应用与实践
【7月更文挑战第8天】自动化测试在API测试中的应用极大地提高了测试效率和质量,为软件的快速迭代和持续交付提供了有力保障。通过合理选择测试工具、制定清晰的测试计划并遵循最佳实践,我们可以充分发挥自动化测试的优势,为软件产品的稳定性和可靠性保驾护航。
|
4天前
|
敏捷开发 Devops 测试技术
自动化测试框架的演进与实践
【7月更文挑战第11天】在软件开发的历程中,自动化测试始终扮演着不可或缺的角色。本文将通过探讨自动化测试框架的发展脉络,揭示其在现代软件工程中的应用与挑战。从早期的线性脚本到今日的模块化框架,我们将一窥自动化测试技术的演进之路,并分享实践中的经验和策略,旨在为读者提供一套实用的自动化测试解决方案。
4 1
|
8天前
|
监控 Java 测试技术
如何构建高效的自动化测试框架:策略与实践
【7月更文挑战第6天】构建高效的自动化测试框架是一个持续的过程,需要不断迭代和优化。通过遵循设计原则、选择合适的关键技术、并遵循科学的实施步骤,我们可以构建出稳定、可靠、易于维护的自动化测试框架,为软件质量的提升和交付周期的缩短提供有力支持。
|
7天前
|
监控 测试技术 持续交付
自动化测试在移动应用开发中的实践
【7月更文挑战第7天】自动化测试在移动应用开发过程中具有重要的作用。通过实施自动化测试,可以提高测试效率、保证测试质量、支持持续集成/持续部署等。然而,在实施自动化测试的过程中也会面临一些挑战,如设备兼容性、测试数据准备和维护成本等。为了克服这些挑战,我们需要采用合适的技术和策略,不断优化和完善自动化测试流程。
|
4天前
|
机器学习/深度学习 人工智能 运维
探索自动化测试的前沿技术与实践
随着软件行业的快速发展,传统的手动测试方法已难以满足日益增长的质量保证需求。自动化测试作为提高测试效率和准确性的关键手段,正逐渐成为软件开发过程中不可或缺的一部分。本文将深入探讨自动化测试的最新技术趋势,分析其在现代软件开发生命周期中的应用,并提供一系列实施策略,旨在帮助读者理解并掌握自动化测试的核心技术和方法。
|
6天前
|
Java jenkins 测试技术
Java中的自动化测试与持续集成实践
Java中的自动化测试与持续集成实践