Syl*_*gue 12 c# testing tdd constants
常量是美丽的人 - 他们可以在一个独特的地方保存一个在代码中随处可用的值.更改该值只需要一个简单的修改.
生活是很酷.
嗯,这是承诺.现实有时是不同的:
LogCompleteFileName常量值更改L:\LOGS\MyApp.log为\\Traces\App208.txt,您将获得两个文件:\\traces\App208.txt对于跟踪和\\traces\App208.txt.log日志...TransactionTimeout将从2分钟更改为4分钟,并且在2分钟后仍然会超时(在花了一天之后,您会发现您还必须更改DBMS的超时和事务管理器的超时...).SleepTimeInMinutes从1到10,你看到没有变化(一个小时左右后,你会发现,不断的名字是误导:粒度不分钟,但毫秒...).CompanyName,比如说Yahoo,Microsoft但自动邮件警报仍然发送给alert@yahoo.com...创建常量是契约.你告诉你的读者,每当他们改变价值时,它仍然会按照他们认为应该的方式运作.
没什么.
当然,你需要测试一下你是不是误导了你的读者.您必须确保隐含合同是正确的.
你如何用TDD实现这一目标?我只是坚持这一点.我可以测试常量(!)值的变化的唯一方法是使该常量变为应用程序设置...... const当我认为该值可以并且将会改变时,我是否必须得出结论:应该避免使用关键字?
你是如何使用TDD测试你的(所谓的)常量的?
提前谢谢了 :)
Jam*_*Ide 12
我可以测试常量(!)值的变化的唯一方法是使应用程序设置保持不变
您在问题中列出的所有用法听起来都像是应用程序设置,而不是常量.常量是一个恒定的值,例如:
const decimal LITERS_PER_HOGSHEAD = 238.480942392;
Run Code Online (Sandbox Code Playgroud)
编辑补充:希望这比我的轻率答案更有帮助.我通常创建一个AppSettings类.这个类中的一些属性是从配置文件中提取的,有些是我不希望改变的设置,有些可能是常量.
public class AppSettings
{
public const decimal GILLS_PER_HOMER = 1859.771248601;
public string HelpdeskPhone
{
get { // pulled from config and cached at startup }
}
public int MaxNumberOfItemsInAComboBox
{
get { return 3; }
}
}
Run Code Online (Sandbox Code Playgroud)
常量有两种:
使用TDD编写代码时,每行生产代码都应该存在,因为首先存在需要编写代码的失败测试.当您重构代码时,一些神奇的值将被提升为常量.其中一些可能也适用于应用程序设置,但为方便起见(代码较少),它们已在代码中配置而不是外部配置文件.
在这种情况下,我编写测试的方式,生产和测试代码将使用相同的常量.测试将指定常量按预期使用.但是测试不会重复常量的值,例如" assert MAX_ITEMS == 4",因为那将是重复的代码.相反,测试将检查某些行为是否正确使用常量.
例如,这是一个示例应用程序(由我编写),它将打印指定长度的Longcat.如您所见,Longcat被定义为一系列常量:
public class Longcat {
// Source: http://encyclopediadramatica.com/Longcat
public static final String HEAD_LINES = "" +
" /\\___/\\ \n" +
" / \\ \n" +
" | # # | \n" +
" \\ @ | \n" +
" \\ _|_ / \n" +
" / \\______ \n" +
" / _______ ___ \\ \n" +
" |_____ \\ \\__/ \n" +
" | \\__/ \n";
public static final String BODY_LINE = "" +
" | | \n";
public static final String FEET_LINES = "" +
" / \\ \n" +
" / ____ \\ \n" +
" | / \\ | \n" +
" | | | | \n" +
" / | | \\ \n" +
" \\__/ \\__/ \n";
...
Run Code Online (Sandbox Code Playgroud)
测试验证常量是否正确使用,但它们不会复制常量的值.如果我更改常量的值,则所有测试都将自动使用新值.(无论Longcat ASCII艺术看起来是否合适,都需要手动验证.虽然您甚至可以通过验收测试自动化,但对于更大的项目来说,这是值得推荐的.)
public void test__Longcat_with_body_size_2() {
Longcat longcat = factory.createLongcat(2);
assertEquals(Longcat.BODY_LINE + Longcat.BODY_LINE, longcat.getBody());
}
public void test__Fully_assembled_longcat() {
Longcat longcat = factory.createLongcat(2);
assertEquals(Longcat.HEAD_LINES + longcat.getBody() + Longcat.FEET_LINES, longcat.toString());
}
Run Code Online (Sandbox Code Playgroud)
同样的应用程序还有一些永远不会改变的常量,例如米和英尺之间的比例.这些值可以/应该硬编码到测试中:
public void test__Identity_conversion() {
int feet1 = 10000;
int feet2 = FEET.from(feet1, FEET);
assertEquals(feet1, feet2);
}
public void test__Convert_feet_to_meters() {
int feet = 10000;
int meters = METERS.from(feet, FEET);
assertEquals(3048, meters);
}
public void test__Convert_meters_to_feet() {
int meters = 3048;
int feet = FEET.from(meters, METERS);
assertEquals(10000, feet);
}
Run Code Online (Sandbox Code Playgroud)
生产代码如下:
public enum LengthUnit {
METERS("m", 1.0), FEET("ft", 0.3048), PETRONAS("petronas", 451.9), LINES("lines", 0.009);
private final String name;
private final double lengthInMeters;
...
public int from(int length, LengthUnit unit) {
return (int) (length * unit.lengthInMeters / this.lengthInMeters);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我没有为Petronas Twin Towers的高度编写任何测试,因为该信息是声明性的(并且声明性数据很少被破坏)并且我已经为转换逻辑编写了测试(参见上文).如果添加更多类似的常量(艾菲尔铁塔,帝国大厦等),它们将由应用程序自动定位,并将按预期工作.