你应该单元测试简单属性吗?

Sam*_*Sam 45 c# unit-testing

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

public string ConnectionString { get; set; }
Run Code Online (Sandbox Code Playgroud)

测试

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

    Assert.Equal(c.ConnectionString, "value");
}
Run Code Online (Sandbox Code Playgroud)

我想我没有看到它的价值.

Ste*_*rne 46

我建议你绝对应该.

  • 什么是今天的汽车财产最终可能会在明天有一个支持领域,而不是你......

  • "你只是在测试编译器或框架"的论点有点像一个稻草人.测试自动属性时你正在做的是从调用者的角度来测试你的类的公共"接口".调用者不知道这是一个带有框架生成的后备存储的自动属性,还是getter/setter中有一百万行复杂代码.因此,调用者正在测试该属性隐含合同 - 如果您将X放入框中,您可以稍后返回X.

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

  • 像这样的测试可能需要一分钟才能完成,所以这并不是很麻烦; 并且您可以轻松地创建一个T4模板,该模板将通过一些反射为您自动生成这些测试.我现在正在研究这样一个工具,为我们的团队节省一些苦差事

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

  • 难道你不想进行前期回归测试,这样当FNG做这样的事情时:


//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;
}
Run Code Online (Sandbox Code Playgroud)

立刻知道他们弄坏了什么?

如果上面似乎设计了一个简单的字符串属性,我个人已经看到了一个自动属性被一个人认为是如此聪明并且想要将它从实例成员更改为静态类成员的包装器的情况(表示数据库连接发生时,更改的重要性并不重要).

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

这导致应用程序编译并发送给客户,因此它很快就失败了.这不是什么大不了的事,但它需要几个小时的支持时间==钱......顺便说一下,那个布偶是我的!

编辑:根据这个线程上的各种对话,我想指出一个读写属性的测试是非常简单的:

[TestMethod]
public void PropertyFoo_StoresCorrectly()
{
   var sut = new MyClass();
   sut.Foo = "hello";
   Assert.AreEqual("hello", sut.Foo, "Oops...");
}
Run Code Online (Sandbox Code Playgroud)

编辑:根据Mark Seeman的Autofixture,您甚至可以在一行中完成

我会提出,如果你发现你拥有如此众多的公共财产,以至于为每一行写下3行,那么你应该质疑你的设计; 如果你依赖另一个测试来表明这个属性的问题,那么

  • 该测试实际上正在测试此属性,或
  • 您将花费更多时间来验证此其他测试是否失败,因为属性不正确(通过调试器等),而不是您在键入上述代码时所花费的
  • 如果某些其他测试允许您立即告知该属性有问题,那么它不是单元测试!

编辑(再次!):正如评论中指出的那样,正确如此,像生成的DTO模型之类的东西可能是上述的例外,因为它们只是用于将数据转移到其他地方的愚蠢的旧桶,而且因为工具创建了它们,测试它们通常毫无意义.

/编辑

最终"它取决于"可能是真正的答案,但需要注意的是,最好的"默认"倾向是"总是这样做"的方法,除了根据具体情况采取的例外情况.

  • 如果人们贬低会对他们为什么不喜欢接受的答案留下某种评论,那将是非常好的... (3认同)
  • 模型类通常只是公共属性的集合,这不是一个糟糕的设计.如果您有一个复杂的域模型,那么最终会有数百个这些次要单元测试,每次重构模型时都需要对其进行维护.如果被测试的"单元"是对象,则可以合理地预期该对象的当前状态对方法的输出有影响.测试这些方法仍然是一个单元测试,即使它们依赖于对象的状态. (2认同)

Ben*_*enM 40

一般来说,没有.应使用单元测试来测试单元的功能.您应该在类上单独测试方法,而不是单独的自动属性(除非您使用自定义行为覆盖getter或setter).

您知道,如果您将语法和setter值设置为正确,则将字符串值分配给自动字符串属性将是有效的,因为这是语言规范的一部分.如果你不这样做,那么你会得到一个运行时错误来指出你的缺陷.

应该设计单元测试来测试代码中的逻辑错误,而不是编译器会捕获的东西.

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

我可以理解TDD纯粹主义者会说你需要测试自动属性.但是,作为一个业务应用程序开发人员,我需要权衡一下,合理地说我可以花费多少时间来编写和执行"琐碎"代码(如自动属性)的测试,而不是合理地解决可能出现的问题的时间长度.不测试.在个人经验中,由于改变普通代码而产生的大多数错误都很容易在99%的时间内修复.出于这个原因,我会说只有单元测试非语言规范功能的积极因素超过了负面因素.

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

  • +1也是,你间接测试这些属性.例如,如果他们没有在其他测试中涵盖,则不需要它们. (3认同)
  • 我认为在内置语言功能(在这种情况下是自动属性)的情况下,根本不需要对它进行单元测试,因为除了测试你知道可以工作的功能之外它没有用处.如果你在开发人员的环境中拥有这个属性,他们都在使用TDD实践,那么他们就知道他们应该在任何时候改变这个属性的行为,然后在单元测试中添加它,当它不再符合语言时规格. (2认同)