英文:
Magic number constant name convention for tests ONE, TWO,.. ONE_HUNDRED vs _1 , _2, _100
问题
所以我正在进行一些代码重构/ Sonar 修复,并且有一些测试包含魔法数字,比如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);
并且我的 NumberConstant 类如下:
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;
这是一个好的折衷方案吗?还是整个方法不正确?你是如何保持测试清晰易懂的?
英文:
so I'm doing some code refactoring/sonar fixes, and there are some tests that contain magic numbers, 5, 123, 567 or whatever, i wanted to create a NumberConstant class where we save numbers used in tests, everything is good we have something like this
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;
the problem is when doing the refactoring, the code is "ok" for SonarQube, but something seems off, the code somehow becomes "cluttered",
i mean just compare these two lines
before
private LocalDateTime endtDateOfFiscalYear2018 = LocalDate.of(2018, Month.DECEMBER, 31).atTime(LocalTime.MAX);
after
private LocalDateTime endtDateOfFiscalYear2018 = LocalDate.of(TWO_THOUSAND_EIGHTEEN, Month.DECEMBER, THIRTY_ONE).atTime(LocalTime.MAX);
I thought a good compromise would be :
private LocalDateTime endtDateOfFiscalYear2018 = LocalDate.of(_2018, Month.DECEMBER, _31).atTime(LocalTime.MAX);
and having my NumberConstant class like this
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;
is this a good compromise or is the whole approach incorrect? what is your approach to keeping your test clean and understandable?
答案1
得分: 4
我认为整个方法是不正确的。
从引入一个命名常量中你得到了什么,其中名称只是重新表达了值?
从文字值中引入一个常量通常有一些好处:
- 你不再看到含义的名字而不是一些魔法数字。
- 它将具有相同含义的相同值的情况分组在一起。例如,您可能会遇到很多地方使用数字10,有些是数字表示的进制,有些是对数值的基数,有些表示十月份,等等。
- 如果以后发现不同的值更好地代表了预期的含义,您可以在一个中央位置更改它。
如果您将所有文字10的出现替换为一个名为TEN或_10的常量,所有这些都将不起作用。例如,您希望永远不会将TEN更改为值20。
因此,需要的不仅仅是对值进行自动盲目替换。您需要了解文字的具体含义,然后引入一个适当的名称来表示这个概念,将所有相同概念的出现替换为一个通用名称。
最初的开发人员应该这样做。如果现在你只是盲目地引入像TEN这样的名称,你只是隐藏了不足,它永远不会得到改进。所以我宁愿Sonar永久地提醒我这个问题,而不是永远隐藏它。
有时候,特别是在测试用例中,我甚至更愿意看到文字4711而不是一个名为SOME_RANDOM_FOUR_DIGIT_NUMBER的常量。
英文:
I think the whole approach is incorrect.
What do you gain from introducing a named constant where the name just rephrases the value?
Introducing a constant from a literal value generally has some benefits:
- Instead of some magic number you see a meaningful name.
- It groups together the situations where that very same value has the same meaning. E.g. you might encounter lots of places using the number 10, some as a digit representation radix, some as the base of a logarithm value, some representing the month of October, and so on.
- If you find out later that a different value better represents the intended meaning, you can change that at one central place.
All this doesn't work if you replace all occurrences of a literal 10 with a constant named TEN or _10. E.g. you'll hopefully never change TEN to have a value of 20.
So, what's needed is more than just some automated, blind replacement of values. You need to understand what that specific occurrence of the literal means, and then introduce an appropriate name for this concept, replacing all occurences of the same concept with a common name.
The original developer should have done that. If now you just blindly introduce names like TEN, you just hide the deficiency, and it'll never be improved. So I'd rather have Sonar permanently remind me of the problem than to hide it forever.
And sometimes, especially in test cases, I'd even prefer to see a literal 4711 than a constant named SOME_RANDOM_FOUR_DIGIT_NUMBER.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论