C# 您应该对简单属性进行单元测试吗?

C# 您应该对简单属性进行单元测试吗?,c#,unit-testing,C#,Unit Testing,您是否应该对类的简单属性进行单元测试,断言设置并检索了一个值?或者这真的只是对语言进行单元测试 示例 public string ConnectionString { get; set; } 测试 public void TestConnectionString() { var c = new MyClass(); c.ConnectionString = "value"; Assert.Equal(c.ConnectionString, "value"); } 我

您是否应该对类的简单属性进行单元测试,断言设置并检索了一个值?或者这真的只是对语言进行单元测试

示例

public string ConnectionString { get; set; }
测试

public void TestConnectionString()
{
    var c = new MyClass();
    c.ConnectionString = "value";

    Assert.Equal(c.ConnectionString, "value");
}

我想我看不出这有什么价值。

我不得不说不。如果这不起作用,你会有更大的问题。我知道我不知道。现在有人会争辩说,例如,如果删除了属性,那么单独使用代码将确保测试失败。但是我会把钱放在这样一个事实上,如果删除了属性,那么单元测试代码将在重构中删除,所以这无关紧要。

一般来说,没有。单元测试应该用来测试单元的功能。您应该对类而不是单个的自动属性进行单元测试(除非您使用自定义行为重写getter或setter)

您知道,如果语法和setter值正确,那么将字符串值指定给自动字符串属性将起作用,因为这是语言规范的一部分。如果您不这样做,那么您将得到一个运行时错误来指出您的缺陷

单元测试应该设计为测试代码中的逻辑错误,而不是编译器无论如何都会捕获的东西

编辑:根据我与该问题公认答案作者的对话,我想补充以下内容。

我能理解TDD纯粹主义者会说您需要测试自动属性。但是,作为一名业务应用程序开发人员,我需要权衡一下,我可以花多少时间为“琐碎”代码(如自动属性)编写和执行测试,与修复不测试可能导致的问题所需的合理时间相比。根据个人经验,99%的时间里,大多数因更改琐碎代码而产生的bug都是琐碎的。出于这个原因,我想说,只有单元测试非语言规范功能的优点大于缺点


如果您在使用TDD方法的快节奏业务环境中工作,那么该团队的工作流程的一部分应该是只测试需要测试的代码,基本上是任何自定义代码。如果有人进入您的类并更改自动属性的行为,他们有责任在该点为其设置单元测试。

除非属性执行任何其他类型的逻辑,否则不会


是的,这就像对语言进行单元测试。否则,测试简单的自动实现属性将毫无意义

您是否坚持严格的TDD实践

如果是,那么您绝对应该在公共getter和setter上编写测试,否则您怎么知道您是否正确地实现了它们


如果没有,您可能仍然应该编写测试。虽然现在的实现很简单,但如果没有测试覆盖简单的get/set操作的功能,就不能保证保持这种状态,因为将来对实现的更改打破了“使用值栏设置属性Foo会导致属性Foo的getter返回值栏”这一不变量单元测试将继续通过。测试本身的实现也很简单,但可以防止将来的更改。

我认为,单元测试(或一般测试)的多少取决于您对代码按设计工作的信心,以及将来代码崩溃的可能性有多大

如果您对代码中断的信心较低(可能是因为代码被外包,并且逐行检查的成本很高),那么单元测试属性可能是合适的


您可以做的一件事是编写一个助手类,该类可以检查类的所有get/set属性,以测试它们是否仍按设计的方式运行。

我建议您绝对应该这样做

  • 今天的汽车产业可能会在明天有一个后盾,而不是你

  • “您只是在测试编译器或框架”这一论点有点像稻草人;从调用方的角度来看,测试auto属性时要做的是测试类的公共“接口”。调用方不知道这是一个带有框架生成的备份存储的自动属性,还是getter/setter中有一百万行复杂代码。因此,调用者正在测试属性所隐含的契约——如果您将X放入框中,您可以稍后将X取回

  • 因此,我们应该包含一个测试,因为我们测试的是我们自己代码的行为,而不是编译器的行为

  • 像这样的测试可能需要一分钟的时间来编写,所以它并不十分繁重;您可以很容易地创建一个T4模板,该模板将通过一点反射自动生成这些测试。实际上,我现在正在开发这样一个工具,以使我们的团队省去一些苦差事

  • 如果你在做纯粹的TDD,那么它会迫使你停下来考虑一下,如果有一个汽车公共财产是最好的事情(提示:通常不是!)

  • 难道你不想做一个预先的回归测试,这样当FNG做这样的事情时:



你立刻就知道他们弄坏了什么东西

如果上面的内容是为一个简单的字符串属性设计的,那么我个人就看到过这样一种情况:一个auto属性被一些人重构了,他们认为自己非常聪明,想把它从一个实例成员改成一个围绕静态类成员的包装器(表示数据库连接时,更改的原因并不重要)

当然,同一个非常聪明的人完全忘记了告诉其他人他们需要调用一个神奇的函数来初始化这个静态成员

这导致应用程序编译并发送给客户
//24-SEP-2013::FNG - put backing field for ConnectionString as we're now doing constructor injection of it
public string ConnectionString
{
   {get { return _connectionString; } }
   {set {_connectionString="foo"; } }//FNG: I'll change this later on, I'm in a hurry
}

///snip

public MyDBClass(string connectionString)
{
   ConnectionString=connectionString;
}
[TestMethod]
public void PropertyFoo_StoresCorrectly()
{
   var sut = new MyClass();
   sut.Foo = "hello";
   Assert.AreEqual("hello", sut.Foo, "Oops...");
}