你应该单元测试类的简单属性,断言是否设置并检索了一个值?或者这真的只是单元测试语言?
示例
public string ConnectionString { get; set; }
测试
public void TestConnectionString()
{
var c = new MyClass();
c.ConnectionString = "value";
Assert.Equal(c.ConnectionString, "value");
}
我想我没有看到它的价值。
答案 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)
我的答案来自前测试经理的观点,目前是开发经理(负责时间和质量的软件交付)观点。我看到人们提到了实用主义。实用主义不是一个好的顾问,因为它可能与懒惰和/或时间压力配对。它可能会以错误的方式引导你。如果你提到实用主义,你必须小心谨慎,将你的意图放在专业和常识的轨道上。它需要谦虚地接受答案,因为它们可能不是你想要听到的。
从我的观点来看,重要的是下一个:
总而言之,没有好的答案。只需要回答其他问题,即可获得可以决定是否需要的临时点。