TDD:任何不断测试的模式?

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的超时和事务管理器的超时...).
  • 您替换SleepTimeInMinutes110,你看到没有变化(一个小时左右后,你会发现,不断的名字是误导:粒度不分钟,但毫秒...).
  • 更微妙:你改变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)


Esk*_*ola 5

常量有两种:

1)便利/可读性的常数

使用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)

2)通用常数

同样的应用程序还有一些永远不会改变的常量,例如米和英尺之间的比例.这些值可以/应该硬编码到测试中:

    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的高度编写任何测试,因为该信息是声明性的(并且声明性数据很少被破坏)并且我已经为转换逻辑编写了测试(参见上文).如果添加更多类似的常量(艾菲尔铁塔,帝国大厦等),它们将由应用程序自动定位,并将按预期工作.