所以我正在做一些代码重构/声纳修复,并且有一些测试包含幻数,5、123、567 或其他什么,我想创建一个 NumberConstant 类,我们在其中保存测试中使用的数字,一切都很好,我们有这样的东西
public static final int ZERO = 0;
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;
public static final int FOUR = 4;
public static final int FIVE = 5;
问题是在进行重构时,SonarQube 的代码"还可以",但似乎有些不对劲,代码不知何故变得"混乱",
我的意思是只是比较这两行
以前
private LocalDateTime endtDateOfFiscalYear2018 = LocalDate.of(2018, Month.DECEMBER, 31).atTime(LocalTime.MAX);
后
private LocalDateTime endtDateOfFiscalYear2018 = LocalDate.of(TWO_THOUSAND_EIGHTEEN, Month.DECEMBER, THIRTY_ONE).atTime(LocalTime.MAX);
我认为一个好的折衷方案是:
private LocalDateTime endtDateOfFiscalYear2018 = LocalDate.of(_2018, Month.DECEMBER, _31).atTime(LocalTime.MAX);
并像这样拥有我的数字常量类
public static final int _0 = 0;
public static final int _1 = 1;
public static final int _2 = 2;
public static final int _3 = 3;
public static final int _4 = 4;
public static final int _5 = 5;
这是一个很好的折衷方案还是整个方法不正确? 您有什么方法可以保持测试干净易懂?
我认为整个方法是不正确的。
从引入命名常量(其中名称只是改写值(中,您会获得什么?
从文本值引入常量通常有一些好处:
- 您看到的不是一些神奇的数字,而是有意义的名称。
- 它将相同值具有相同含义的情况组合在一起。 例如,您可能会遇到很多使用数字 10 的地方,有些作为数字表示基数,有些作为对数值的底,有些表示十月,等等。
- 如果以后发现不同的值更能代表预期的含义,则可以在一个中心位置进行更改。
如果将文本 10 的所有匹配项替换为名为 TEN 或 _10 的常量,则所有这些操作都不起作用。 例如,您希望永远不会将 TEN 更改为值 20。
因此,我们需要的不仅仅是一些自动化的、盲目的价值替换。您需要了解文字的特定出现的含义,然后为此概念引入适当的名称,将同一概念的所有出现替换为通用名称。
原始开发人员应该这样做。如果现在你只是盲目地引入像TEN这样的名字,你只是隐藏了不足,它永远不会得到改善。所以我宁愿让声纳永远提醒我这个问题,也不愿永远隐藏它。
有时,尤其是在测试用例中,我甚至更喜欢看到文字 4711 而不是名为 SOME_RANDOM_FOUR_DIGIT_NUMBER 的常量。