• 单元测试篇2-TDD三大法则解密


    引言

    在我们上一篇文章了解了单元测试的基本概念和用法之后,今天我们来聊一下 TDD(测试驱动开发)

    测试驱动开发 (TDD)

    测试驱动开发英文全称是Test Driven Development 简称 TDD。

    根据 UncleBob 的 TDD 描述总结

    我们先创建一个测试项目

    直接在 VS 创建即可,可以参考上一篇文章的创建过程

    The Three Laws of TDD.

    • You are not allowed to write any production code unless it is to make a failing unit test pass.
    • You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
    • You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

    这是本文的描述的三个 TDD 开发的原则,它确保了代码的质量和可维护性。

    下面对这三条内容做详细的解释

    • 第一条规则指出 不允许编写任何的生产代码,除非是在让单元测试通过时。
      • 简单理解就是在编写任何实际的业务逻辑代码之前,必须先编写一个或者多个单元测试,这些单元测试因为没有实现所以会失败,有了失败的单元测试之后我们才可以去在生产代码中实现业务逻辑
    • 第二条规则指出 不允许编写比失败所需更多的单元测试代码;编译失败也是失败:

      • 这可以理解为 在编写单元测试时,应该只编写足够使测试失败的最小代码量。这样,可以立即知道新写的生产代码是否解决了问题。编译失败同样被视为测试失败,因为编译不通过意味着代码无法运行。

    那一个我们上一章节的一个数学计算类的例子

    
    namespace dotNetParadise_TDD.Test;
    
    public class MathCalculatorTests
    {
        [Fact]
        public void Add_TwoNumbers_ReturnSum()
        {
            // Arrange
            var calculator = new MathCalculator();
    
            // Act
            var result = calculator.Add(3, 5);
    
            // Assert
            Assert.Equal(8, result);
        }
    }
    

    因为我们没有 MathCalculator 这个类的实现所以,代码会编译失败。

    image

    在这个示例中,我们展示了如何编写一个简单的单元测试,测试 Calculator 类的 Add 方法是否能够正确地将两个数字相加并返回正确的结果。根据 TDD 原则,我们只编写了必要部分的代码来测试这个功能,并且在这个阶段测试应该会失败,因为 Add 方法还未实现。编译失败也会被视为测试失败,这强调了编写足够简洁和精确的单元测试的重要性,符合第二条准则。

    • 第三条规则指出 不允许编写比通过单个失败单元测试所需更多的生产代码
      可以理解为在编写生产代码时,只需编写足够让失败的单元测试通过的代码,而不是一次性编写完整的功能。这有助于保持代码的小步前进,并且每次更改都有明确的测试验证。

    现在把MathCalculator类中增加一个参数*2 即翻倍的一个功能

    第一步编写一个单元测试方法,

        [Fact]
        public void DoubleNumber_WhenGivenSingleNumber_ReturnsDouble()
        {
            // Arrange
            var calculator = new MathCalculator();
    
            // Act
            var result = calculator.DoubleNumber(2);
    
            // Assert
            Assert.Equal(4, result);
        }
    

    第二步 编写足够让失败的单元测试通过的代码

    namespace dotNetParadise_TDD.Test;
    
    public class MathCalculator
    {
        public int DoubleNumber(int number)
        {
            throw new NotImplementedException();
        }
    }
    
    

    接下来运行单元测试

     dotNetParadise_TDD.Test.MathCalculatorTests.DoubleNumber_WhenGivenSingleNumber_ReturnsDouble
       源: MathCalculatorTests.cs 行 20
       持续时间: 371 毫秒
    
      消息: 
    System.NotImplementedException : The method or operation is not implemented.
    
      堆栈跟踪: 
    MathCalculator.DoubleNumber(Int32 number) 行 7
    MathCalculatorTests.DoubleNumber_WhenGivenSingleNumber_ReturnsDouble() 行 26
    RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
    MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    

    结果和预期一样,测试没有成功

    image

    现在来重构一下这个方法

        public int DoubleNumber(int number)
        {
            //throw new NotImplementedException();
            return 2 * number;
        }
    

    再次运行单元测试

    image

    可以看到单元测试成功了!

    TDD 开发流程图

    最后

    通常我们进行单元测试的时候都是先写业务逻辑,然后再单元测试,当系统业务逻辑变复杂之后可能会遗漏一些测试 CaseTDD 的出现就是解决这个问题,通过测试 Case 来写重构业务代码的模式。

    这三个规则确保了 TDD 的核心循环:红(测试失败)、绿(测试通过)、重构。通过不断地重复这个过程,开发者能够编写出高质量、可测试、易于维护的代码。

    本文完整源代码
    image


    __EOF__

  • 本文作者: 董瑞鹏
  • 本文链接: https://www.cnblogs.com/ruipeng/p/18118155
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    java Maven入门笔记
    数据库表的字符集编码报错问题
    【监听服务器】自动重启脚本
    1.1 网页的基本概念
    区块链技术介绍和用法
    HTTP状态码大全及分类
    基于微信小程序的宠物交易商城系统设计与实现(源码+lw+部署文档+讲解等)
    SpringMvc向request域中设置数据
    ML.NET 3.0 增强了深度学习和数据处理能力
    Vue Cli安装和node-sass、less-loader、sass-loader安装
  • 原文地址:https://www.cnblogs.com/ruipeng/p/18118155