C# TDD:是否有持续测试的模式?

C# TDD:是否有持续测试的模式?,c#,testing,tdd,constants,C#,Testing,Tdd,Constants,常量是美丽的人——它们可以在一个独特的地方保存一个在代码中随处可见的值。更改该值只需要一次简单的修改 生活很酷 这就是承诺。现实有时是不同的: 您将LogCompleteFileName常量值从L:\LOGS\MyApp.log更改为\\Traces\App208.txt,您将得到两个文件:用于跟踪的\\Traces\App208.txt,以及用于日志的\\Traces\App208.txt.log 您将TransactionTimeout从2分钟更改为4分钟,但2分钟后仍然会有一个超时(花了

常量是美丽的人——它们可以在一个独特的地方保存一个在代码中随处可见的值。更改该值只需要一次简单的修改

生活很酷

这就是承诺。现实有时是不同的:

  • 您将
    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测试您的(所谓的)常量

非常感谢:)

测试常量(!)值的更改的唯一方法是将该常量设置为应用程序设置

在我看来,您在问题中列出的所有用途听起来像是应用程序设置,而不是常量。常数是一个常数,例如:

const decimal LITERS_PER_HOGSHEAD = 238.480942392;
编辑添加:希望这比我轻率的回答更有帮助。我通常创建一个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; }
    }
}

从我读到的你的问题来看,这与TDD无关。您描述的用法不是一个真正的常量,而是一个配置值,因此在这些情况下,您不应该使用
const
修饰符。

我觉得您使用常量主要是为了说明配置设置。这是ConfigurationManager的理想选择,但也很难用于测试

我建议使用以下方法:

const String SomeValue = "TESTCONSTANT";

static class ConfigurationSettings
{
    static String SomeProperty
    {
        get
        {
           var result = SomeValue;
           if (ConfigurationManager.AppSettings["SOMEKEY"] != null)
               result = ConfigurationManager.AppSettings["SOMEKEY"];
           return result;
        }
    }
}
有几件事

首先,TDD和TDD促进的紧急设计是将您的职责分离,应用干式和依赖注入

对常量进行单元测试很容易,而且可能有点毫无意义

但在我看来,测试另一个单元对该常数的评估不是单元测试。这是一个集成测试。在其他单位中测试常量值将由模拟或存根覆盖

其次,你的例子多种多样:

您的日志示例仅使用1个文件。只是有两个存在。如果要求只存在一个文件,那么您可以为此制作一个测试

事务超时测试应通过集成测试进行。它应该表明您的原始测试不是问题所在

更改公司名称是可以的,因为它与公司名称有关。域名应该而且可能是不同的常量


正如其他人提到的,在测试其他类时,在我的周围传递一个配置类可能有助于mock/stub。

这是因为所有这些东西都不是常量。。。实际上是:

  • G(6.67300×10-11 m3 kg-1 s-2)
  • c(299 792 458米/秒)
  • pi(3.1415926535897931)
  • L(6.0221415×1023 mol-1)

如果其中任何一种情况发生变化,请不要担心,应用程序崩溃将是最后一个重要因素xD

有两种常量:

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";
...
1) 为方便/可读性而设置的常量 当使用TDD编写代码时,每行生产代码都应该存在,因为首先有一个失败的测试要求编写该代码。当您重构代码时,一些神奇的值将被提升为常量。其中一些可能还可以用作应用程序设置,但为了方便(代码更少),它们是在代码中配置的,而不是在外部配置文件中配置的

在这种情况下,按照我编写测试的方式,生产代码和测试代码都将使用相同的常量。测试将指定按预期使用常数。但是测试不会重复常量的值,例如“
assert MAX_ITEMS==4
”,因为这将是重复的代码。相反,测试将检查某些行为是否正确使用常量

例如,是一个示例应用程序(由我编写),它将打印指定长度的。如您所见,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";
...
这些测试验证了常数的使用是否正确,但不会重复常数的值。如果我更改常量的值,所有测试将自动使用新值。(至于Longcat ASCII艺术是否正确,则需要手动验证。尽管您甚至可以通过验收测试实现自动化,这对于更大的项目来说是值得推荐的。)

2) 普适常数 同一个应用程序也有一些常数,它们从来都不是e
    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);
    }
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);
    }
}
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void DefaultValue_Equals_8()
{
     Assert.AreEqual<int>(8, MyNamespace.MyClass.DefaultValue);
}
namespace MyNamespace
{
    public class MyClass
    {
        public const int DefaultValue = 8;
    }
}
Assert.AreEqual<decimal>(29.5276, converter.metresToFeet(9))