Day 28-Unit Test 应用於使用重构与测试手法优化 C# Code-2 (情境及应用-8)

Unit Test 应用於使用重构与测试手法优化 C# Code-2-前言

昨天有提到我们在 Console 执行应用程序时,可以依序输入 ID、名字、数学数值、文学数值与 isCountry 布林值,而後会执行计算平均值的方法,并给出相对应的平均值又或是提供错误讯息;然而,该方法里面牵涉的商业逻辑,各参数检验是否为合理彼此并没有相对的关系,但以被绑在同一只方法,这样对於系统的维护困难(假设随着功能的扩大,里面有 20-30 个参数要检验),对於测试码的撰写也是极其复杂的。因此,我们今天先重构第一版的商业逻辑与测试码。


Unit Test 应用於使用重构与测试手法优化 C# Code-2-测试码

昨天 Day-27 流程图有提到,我们在重构完程序码後需要跑测试码来验证重构後的程序码是符合预期的结果,那在 Day 19 Roy Osherove 曾提到重构是「在不改变程序码功能的前提下,修改程序码的动作。」;因此,我们要先撰写第一版的测试,以验证目前的行为在测试下的结果,如下:

public class DemoCalculateTests_Ver1
{
    [Test]
    public void NormalCaseTest()
    {
        // Arrange
        string txtID = "Day-28";

        string txtName = "SunShineYen";

        string txtMath = "8";

        string txtLiteral = "4";

        string isCountry = "true";

        DemoCalculate testObject 
              = new DemoCalculate(txtID, txtName, txtMath, txtLiteral, isCountry);

        // Act
        string result = testObject.Calculate();

        // Assert
        Assert.AreEqual(result, "Day-28 SunShineYen 6.5");
    }

    [Test]
    public void FailCaseTest_MathIsNotNumeric()
    {
        // Arrange
        string txtID = "Day-28";

        string txtName = "SunShineYen";

        string txtMath = "Haha";

        string txtLiteral = "4";

        string isCountry = "true";

        DemoCalculate testObject 
              = new DemoCalculate(txtID, txtName, txtMath, txtLiteral, isCountry);

        // Act
        string result = testObject.Calculate();

        // Assert
        Assert.AreEqual(result, "发生错误!数学数值应该是个 numeric!");
    }

    [Test]
    public void FailCaseTest_MathIsInZeroToTen()
    {
        // Arrange
        string txtID = "Day-28";

        string txtName = "SunShineYen";

        string txtMath = "12";

        string txtLiteral = "4";

        string isCountry = "true";

        DemoCalculate testObject 
              = new DemoCalculate(txtID, txtName, txtMath, txtLiteral, isCountry);

        // Act
        string result = testObject.Calculate();

        // Assert
        Assert.AreEqual(result, "发生错误!数学数值应该介於 0 ~ 10 之间!");
    }
    
    // ...
}

执行结果:

https://ithelp.ithome.com.tw/upload/images/20210928/20127378pcAKjm88LT.png


Unit Test 应用於使用重构与测试手法优化 C# Code-2-重构後的程序码(第一版)

上面测试码为示意,测试的情境还可以撰写数个测试方法如文学数值是否为 Numeric、文学数值是否介於 0-10 等。而接下来要探讨的是撰写重构程序码,而大致上要做的项目有几点,如下:

  1. 检测数学数值是否符合 Numeric Type 与介於 0~10 之间
  2. 检测文学数值是否符合 Numeric Type 与介於 0~10 之间
  3. Country 平均计算方法
  4. City 平均计算方法

因此,程序码如下:

namespace HelloRefactor
{
    class Program
    {
        // ...

    public class DemoCalculate_Ver2
    {
        private string txtID;

        private string txtName;

        private string txtMath;

        private string txtLiteral;

        private string isCountry;

        public DemoCalculate_Ver2(string inTxtID, string inTxtName, string inTxtMath, string inTxtLiteral, string inIsCountry)
        {
            txtID = inTxtID;

            txtName = inTxtName;

            txtMath = inTxtMath;

            txtLiteral = inTxtLiteral;

            isCountry = inIsCountry;
        }

        public string Calculate()
        {
            string MathInputValidResult = MathInputValid(txtMath);

            string LiteralInputValidResult = LiteralInputValid(txtLiteral);

            if (MathInputValidResult != "没错误")
            {
                return MathInputValidResult;
            }

            if (LiteralInputValidResult != "没错误")
            {
                return LiteralInputValidResult;
            }

            if (Convert.ToBoolean(isCountry))
            {
                return txtID + " " + txtName + " " + CountryAvg(Convert.ToDouble(txtMath), Convert.ToDouble(txtLiteral)).ToString();
            }
            else
            {
                return txtID + " " + txtName + "  " + CityAvg(Convert.ToDouble(txtMath), Convert.ToDouble(txtLiteral)).ToString();
            }
        }

        private string MathInputValid(string txtMath)
        {
            double result;

            if (!double.TryParse(txtMath, out result))
            {
                return "发生错误!数学数值应该是个 numeric!";
            }

            if (((Convert.ToDouble(txtMath) > 10)) || (Convert.ToDouble(txtMath) < 0))
            {
                return "发生错误!数学数值应该介於 0 ~ 10 之间!";
            }

            return "没错误";
        }

        private string LiteralInputValid(string txtLiteral)
        {
            double result;

            if (!double.TryParse(txtLiteral, out result))
            {
                return "发生错误!文学数值应该是个 numeric!";
            }

            if (((Convert.ToDouble(txtLiteral) > 10)) || (Convert.ToDouble(txtLiteral) < 0))
            {
                return "发生错误!文学数值应该介於 0 ~ 10 之间!";
            }

            return "没错误";
        }

        private double CountryAvg(double dbMath, double dbLiteral)
        {
            return (dbMath + dbLiteral + 1) / 2;
        }

        private double CityAvg(double dbMath, double dbLiteral)
        {
            return (dbMath + dbLiteral) / 2;
        }
    }
}

因此,把一开始所撰写的测试码,里面的 DemoCalculate 改成 DemoCalculate_Ver2,跑出来的测试结果如下:

https://ithelp.ithome.com.tw/upload/images/20210928/201273780TPBuH4wlU.png

而这样抽出检验参数的好处是,我们在撰写新的测试方法时,可以单独针对每个参数的检验方式写相对应的测试,若参数多达 20-30 种时,出错也可以找出相对应的问题并修改程序码,明天会在继续探讨如何更精进程序码。


<<:  JavaScript入门 Day23_if判断3

>>:  D28 - 如何打包 Apps Script 的程序码?(一) 变成扩充功能似的 UI 按键

@Day28 | C# WixToolset + WPF 帅到不行的安装包 [改版本号码却跳出旧版本]

我在第二次改版本号的时候,发现了这个问题, 像挥之不去的苍蝇一样…死黏着 就像是上面那个他自己跳出来...

进击的软件工程师之路-软件战斗营 第十三周

学习进度 资料结构 泛型 通配字元 Android Studio RecyclerView Recy...

App Inventor 学习笔记 1 : 显示 List 里的资料

AI2的List很像阵列, 这个App记录读取List的方式 1.使用到的元件: Layout -&...

Re: 新手让网页 act 起来: Day14 - Lift state

前言 刚学习 React 的时候,一定会碰到一个小问题,就是当我们有个值需要存在在两个元件之间,该怎...

DAY16:Pytorch transforms(上)

torchvision.transforms transforms可以用来改变样本的多样性,例如:旋...