测试 ONE、TWO、.. ONE_HUNDRED 与 _1、_2、_100 的幻数常量名称约定
Magic number constant name convention for tests ONE, TWO,.. ONE_HUNDRED vs _1 , _2, _100
所以我正在做一些代码 refactoring/sonar 修复,并且有一些测试包含幻数,5、123、567 或其他任何东西,我想创建一个 NumberConstant class 我们在其中保存测试中使用的数字,一切都很好我们有这样的东西
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 的代码是 "ok",但似乎有些不对劲,代码不知何故变成了 "cluttered",
我的意思是只比较这两行
之前
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);
并让我的 NumberConstant class 像这样
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这样的名字,只是掩盖了自己的不足,永远不会得到改善。所以我宁愿让 Sonar 永久提醒我这个问题,也不愿永远隐藏它。
有时,尤其是在测试用例中,我什至更愿意看到文字 4711 而不是名为 SOME_RANDOM_FOUR_DIGIT_NUMBER.
的常量
所以我正在做一些代码 refactoring/sonar 修复,并且有一些测试包含幻数,5、123、567 或其他任何东西,我想创建一个 NumberConstant class 我们在其中保存测试中使用的数字,一切都很好我们有这样的东西
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 的代码是 "ok",但似乎有些不对劲,代码不知何故变成了 "cluttered",
我的意思是只比较这两行
之前
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);
并让我的 NumberConstant class 像这样
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这样的名字,只是掩盖了自己的不足,永远不会得到改善。所以我宁愿让 Sonar 永久提醒我这个问题,也不愿永远隐藏它。
有时,尤其是在测试用例中,我什至更愿意看到文字 4711 而不是名为 SOME_RANDOM_FOUR_DIGIT_NUMBER.
的常量