是否应该对简单属性进行单元测试
本文关键字:单元测试 属性 简单 是否 | 更新日期: 2023-09-27 18:32:32
是否应该对类的简单属性进行单元测试,断言设置和检索值?或者这真的只是对语言进行单元测试吗?
例
public string ConnectionString { get; set; }
测试
public void TestConnectionString()
{
var c = new MyClass();
c.ConnectionString = "value";
Assert.Equal(c.ConnectionString, "value");
}
我想我看不到其中的价值。
我建议你绝对应该这样做。
-
今天什么是汽车属性,明天可能会有一个支持场,而不是你......
-
恕我直言,"你只是在测试编译器或框架"的论点有点像稻草人;当你测试自动属性时,你正在做的事情,从调用者的角度来看,是测试你的类的公共"接口"。调用方不知道这是否是具有框架生成的后备存储的 auto 属性,或者 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;
}
你立即知道他们破坏了什么?
如果上述内容对于一个简单的字符串属性似乎是人为的,我个人见过这样一种情况,即 auto-属性被那些认为自己非常聪明并希望将其从实例成员更改为静态类成员周围的包装器的人重构(表示发生的数据库连接,更改的共振并不重要(。
当然,那个非常聪明的人完全忘记告诉其他人他们需要调用一个魔术函数来初始化这个静态成员。
这导致应用程序编译并交付给客户,因此它立即失败。没什么大不了的,但它花费了几个小时的支持时间==金钱....顺便说一下,那个布偶是我!
编辑:根据此线程上的各种对话,我想指出读写属性的测试非常简单:
[TestMethod]
public void PropertyFoo_StoresCorrectly()
{
var sut = new MyClass();
sut.Foo = "hello";
Assert.AreEqual("hello", sut.Foo, "Oops...");
}
编辑:你甚至可以按照马克·西曼的自动夹具在一行中做到这一点
我认为,如果你发现你拥有如此多的公共属性,以至于写像上面这样的 3 行是一件苦差事,那么你应该质疑你的设计;如果依赖另一个测试来指示此属性存在问题,则
- 测试
- 实际上是在测试此属性,或者
- 您将花费更多的时间来验证此其他测试是否因属性不正确(通过调试器等(而失败,而不是花费在上述代码中键入 的时间
- 如果其他测试允许您立即判断属性有故障,则不是单元测试!
编辑(再次!(:正如评论中指出的那样,正确的是,生成DTO模型之类的东西可能是上述的例外,因为它们只是愚蠢的旧桶,用于将数据转移到其他地方,而且由于工具创建了它们,测试它们通常毫无意义。
/编辑
最终,">视情况而定"可能是真正的答案,需要注意的是,最好的"默认"倾向是"总是这样做"的方法,除了在知情的情况下逐案采取的方法。
一般来说,没有。应使用单元测试来测试单元的功能。您应该在类而不是单个自动属性上单元测试方法(除非您使用自定义行为覆盖 getter 或 setter(。
您知道,如果语法和 setter 值正确,则将字符串值分配给自动字符串属性将起作用,因为这是语言规范的一部分。如果不这样做,则会收到运行时错误以指出您的缺陷。
单元测试应该设计为测试代码中的逻辑错误,而不是编译器无论如何都会捕获的错误。
编辑:根据我与此问题接受答案的作者的对话,我想添加以下内容。
我可以理解TDD纯粹主义者会说你需要测试自动属性。但是,作为一名业务应用程序开发人员,我需要合理地权衡我可以花在编写和执行"琐碎"代码(如自动属性(测试上的时间与修复可能因不测试而引起的问题所花费的时间。根据个人经验,大多数由更改琐碎代码引起的错误在 99% 的时间内修复起来都是微不足道的。出于这个原因,我会说只有单元测试非语言规范功能的好处大于缺点。
如果您在使用 TDD 方法的快节奏业务环境中工作,那么该团队工作流程的一部分应该是只测试需要测试的代码,基本上是任何自定义代码。如果有人进入您的类并更改自动属性的行为,他们有责任在此时为其设置单元测试。
我不得不说不。如果这不起作用,你就会遇到更大的问题。我知道我没有。现在有些人会争辩说,例如,如果删除属性,单独使用代码可以确保测试失败。但是我会把钱花在这样一个事实上,如果删除该属性,单元测试代码将在重构中删除,所以这无关紧要。
您是否遵守严格的TDD实践?
如果是,那么你绝对应该在公共getter和setter上编写测试,否则你怎么知道你是否正确实现了它们?
如果没有,您可能仍然应该编写测试。尽管今天的实现是微不足道的,但不能保证保持如此,并且如果没有涵盖简单get/set操作功能的测试,当将来对实现的更改打破了"使用值Bar设置属性Foo导致属性Foo返回值Bar的getter"的不变量时,单元测试将继续通过。测试本身也是微不足道的实现,但可以防止未来的变化。
我看到的方式是,单元测试(或一般测试(的程度取决于您对代码按设计工作的信心以及将来中断的可能性有多大。
如果您对代码中断的置信度较低(可能是由于代码已外包并且逐行检查的成本很高(,那么单元测试属性可能是合适的。
一旦你可以做的是编写一个帮助程序类,该类可以遍历类的所有 get/set 属性,以测试它们是否仍按设计运行。
除非属性执行任何其他类型的逻辑,否则不会。
是的,这就像对语言进行单元测试。否则测试简单的自动实现属性将完全没有意义。
根据《使用 .NET 中的示例进行单元测试的艺术》一书,单元测试不涵盖任何类型的代码,它侧重于逻辑代码。那么,什么是逻辑代码?
逻辑代码是任何包含某种逻辑的代码段,尽管它可能很小。如果它具有一个或多个 以下:IF 语句、循环、开关或案例语句, 计算或任何其他类型的决策代码。
一个简单的 getter/setter 是否包装了任何逻辑?答案是:
属性(Java 中的 getter/setter(是代码的很好的例子,它们 通常不包含任何逻辑,因此不需要测试。但 注意:一旦您在住宿内添加任何检查,您就会需要 确保正在测试逻辑。
我的回答是从前测试经理的角度,目前是开发经理(负责时间和质量的软件交付(的观点。我看到人们提到实用主义。实用主义不是一个好的顾问,因为它可能与懒惰和/或时间压力配对。它可能会把你引向错误的道路。如果你提到实用主义,你必须小心翼翼地让你的意图保持在专业精神和常识的轨道上。接受答案需要谦卑,因为它们可能不是你想听到的。
从我的角度来看,重要的是下一个:
- 您应该尽早发现缺陷。这样做,您必须应用适当的测试策略。如果是测试属性,则必须测试属性。如果没有,那就不要这样做。两者都有代价。
- 您的测试应该简单快捷。在构建时测试的代码中较大的部分(单元、集成等(越好。
- 您应该进行根本原因分析以回答以下问题,并保护您的组织免受当前类型的错误的影响。别担心,会出现另一种类型的缺陷,总会有教训需要吸取。
- 根本原因是什么?
- 下次如何避免?
- 另一个方面是创建/维护测试的成本。不测试属性,因为它们维护起来很无聊和/或你有数百个属性是荒谬的。您应该创建/应用使木刻工作而不是人工的工具。通常,您始终必须增强环境以提高效率。
- 其他人说的不是好的顾问——不管马丁·福勒还是西曼说的——他们所处的环境我很确定和你不一样。你必须利用你的知识和经验来设置什么对你的项目有利,以及如何让它变得更好。如果你应用一些东西,因为它们是由你尊重的人说的,甚至没有经过深思熟虑,你会发现自己陷入了深深的麻烦。我并不是说你不需要建议和/或其他人的帮助或意见,你必须运用常识来应用它们。
- TDD 不回答两个重要问题,但是,BDD 确实会回答以下问题。但是,如果您只遵循一个,您将无法按时和质量交付。所以不管你是否是纯粹的TDD家伙。
- 必须测试什么?(它说一切都必须测试-我认为答案错误(
- 何时必须完成测试?
总而言之,没有好的答案。只是您必须回答的其他问题才能获得能够决定是否需要的临时点。