【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月前
|
人工智能 自然语言处理 测试技术
从人工到AI驱动:天猫测试全流程自动化变革实践
天猫技术质量团队探索AI在测试全流程的落地应用,覆盖需求解析、用例生成、数据构造、执行验证等核心环节。通过AI+自然语言驱动,实现测试自动化、可溯化与可管理化,在用例生成、数据构造和执行校验中显著提效,推动测试体系从人工迈向AI全流程自动化,提升效率40%以上,用例覆盖超70%,并构建行业级知识资产沉淀平台。
从人工到AI驱动:天猫测试全流程自动化变革实践
|
7月前
|
数据采集 存储 人工智能
从0到1:天猫AI测试用例生成的实践与突破
本文系统阐述了天猫技术团队在AI赋能测试领域的深度实践与探索,讲述了智能测试用例生成的落地路径。
从0到1:天猫AI测试用例生成的实践与突破
|
8月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
373 19
|
8月前
|
Java 测试技术 API
自动化测试工具集成及实践
自动化测试用例的覆盖度及关键点最佳实践、自动化测试工具、集成方法、自动化脚本编写等(兼容多语言(Java、Python、Go、C++、C#等)、多框架(Spring、React、Vue等))
694 6
|
8月前
|
人工智能 边缘计算 搜索推荐
AI产品测试学习路径全解析:从业务场景到代码实践
本文深入解析AI测试的核心技能与学习路径,涵盖业务理解、模型指标计算与性能测试三大阶段,助力掌握分类、推荐系统、计算机视觉等多场景测试方法,提升AI产品质量保障能力。
|
8月前
|
人工智能 自然语言处理 测试技术
AI测试平台的用例管理实践:写得清晰,管得高效,执行更智能
在测试过程中,用例分散、步骤模糊、回归测试效率低等问题常困扰团队。霍格沃兹测试开发学社推出的AI测试平台,打通“用例编写—集中管理—智能执行”全流程,提升测试效率与覆盖率。平台支持标准化用例编写、统一管理操作及智能执行,助力测试团队高效协作,释放更多精力优化测试策略。目前平台已开放内测,欢迎试用体验!
|
9月前
|
人工智能 资源调度 jenkins
精准化回归测试:大厂实践与技术落地解析
在高频迭代时代,全量回归测试成本高、效率低,常导致关键 bug 漏测。精准化测试通过代码变更影响分析,智能筛选高价值用例,显著提升测试效率与缺陷捕获率,实现降本增效。已被阿里、京东、腾讯等大厂成功落地,成为质量保障的新趋势。
|
9月前
|
存储 机器学习/深度学习 监控
公司监控软件有哪些?监测方案:基于布隆过滤器的 C# 异常行为检测实践探索
本文探讨了布隆过滤器在公司监控软件中的技术应用,介绍其原理、优势及C#实现代码,助力企业高效构建数据安全防护体系。
248 0
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
421 3
|
9月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
2018 0