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

时间:2013-09-23 19:55:21

标签: c# unit-testing

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

示例

public string ConnectionString { get; set; }

测试

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

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

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

8 个答案:

答案 0 :(得分:43)

我建议你绝对应该。

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

  • “你只是在测试编译器或框架”的论点是一个简单的问题;测试自动属性时你正在做的是从调用者的角度来测试你的类的公共“接口”。调用者不知道这是一个带有框架生成的后备存储的自动属性,还是getter / setter中有一百万行复杂代码。因此调用者正在测试属性隐含的合同 - 如果你把X放入框中,你可以稍后再回来。

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

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

  • 如果你正在使用纯TDD,那么它会迫使你停下片刻,考虑一下自动公共财产是否是最好的事情(提示:它通常不是!)

    < / LI>
  • 您是否宁愿进行前期回归测试,以便当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;
}

立即知道他们破坏了什么?

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

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

这导致应用程序编译并发送给客户,然后迅速失败。这不是一个大问题,但它需要几个小时的支持时间==钱.... 顺便说一下,那个布偶是我!

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

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

编辑:根据Mark Seeman的Autofixture

,您甚至可以在一行中完成

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

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

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

<强> /修改

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

答案 1 :(得分:38)

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

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

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

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

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

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

答案 2 :(得分:3)

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

答案 3 :(得分:3)

您是否遵守严格的TDD做法?

如果是,那么绝对应该对公共getter和setter进行测试,否则你怎么知道你是否正确实现了它们?

如果不是,你仍然应该编写测试。虽然今天的实现是微不足道的,但是不能保证保持这样,并且如果没有测试覆盖简单的获取/设置操作的功能,当未来的实现更改破坏了“使用值设置属性Foo”的不变量时属性Foo的getter返回值Bar“单元测试将继续通过。测试本身实施,但是要防范未来的变化。

答案 4 :(得分:2)

我看到的方式是,单元测试(或一般测试)的程度取决于代码如何按设计运行,以及将来破坏它的可能性有多大。

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

你可以做的就是编写一个帮助器类,它可以遍历类的所有get / set属性,以测试它们是否仍按设计行事。

答案 5 :(得分:1)

除非属性执行任何其他类型的逻辑,否则没有。

是的,这就像单元测试语言一样。否则,测试简单的自动实现属性将完全没有意义。

答案 6 :(得分:1)

根据书籍The Art of Unit Testing With Examples in .NET,单元测试不涉及任何类型的代码,它侧重于逻辑代码。那么,什么是逻辑代码

  

逻辑代码是其中包含某种逻辑的任何代码,尽管它可能很小。它是逻辑代码,如果它有一个或多个   以下:IF语句,循环,开关或case语句,   计算或任何其他类型的决策代码。

一个简单的getter / setter是否包含任何逻辑?答案是:

  

属性(Java中的getter / setter)是代码的好例子   通常不包含任何逻辑,因此不需要测试。但   小心:一旦你在房产内添加任何支票,你就会想要   确保正在测试逻辑。

答案 7 :(得分:0)

我的答案来自前测试经理的观点,目前是开发经理(负责时间和质量的软件交付)观点。我看到人们提到了实用主义。实用主义不是一个好的顾问,因为它可能与懒惰和/或时间压力配对。它可能会以错误的方式引导你。如果你提到实用主义,你必须小心谨慎,将你的意图放在专业和常识的轨道上。它需要谦虚地接受答案,因为它们可能不是你想要听到的。

从我的观点来看,重要的是下一个:

  • 你应该尽早发现缺陷。这样做你必须采用适当的测试策略。如果它正在测试属性,那么您必须测试属性。如果没有,那就不要这样做。两者都有价格。
  • 您的测试应该简单快捷。在构建时测试的代码的更大部分(单元,集成等)更好。
  • 您应该进行根本原因分析,以回答以下问题,并使您的组织免受当前类型的错误的影响。别担心,会出现另一种类型的缺陷,总会有经验教训。
    • 根本原因是什么?
    • 下次怎么避免呢?
  • 另一方面是创建/维护测试的成本。不测试属性,因为它们很难维护和/或你有数百个属性是荒谬的。您应该创建/应用工具,这使得木刻工作而不是人工。一般而言,您必须始终改善环境,以提高效率。
  • 其他人说的不是好顾问 - 对于Martin Fowler或Seeman是否说过这件事并不重要 - 他们所处的环境我确定与你所处的不一样。你必须使用您的知识和经验,以设置对您的项目有益的方法以及如何使其更好。如果你申请的东西是因为人们说你是尊重的,你甚至没有考虑过,你会发现自己陷入了深深的麻烦。我不是说你不需要建议和/或其他人的帮助或意见,你必须运用常识来应用它们。
  • TDD没有回答两个重要问题,但BDD确实为您提供了以下问题的答案。但是,如果你只跟随一个,你就不会在时间和质量上得到交付。所以你是否是纯粹的TDD家伙并不重要。
    • 必须测试什么? (它说一切都必须经过测试 - 在我看来是错误的答案)
    • 何时必须完成测试?

总而言之,没有好的答案。只需要回答其他问题,即可获得可以决定是否需要的临时点。