你应该对简单的属性进行单元测试吗? [英] Should you Unit Test simple properties?

查看:18
本文介绍了你应该对简单的属性进行单元测试吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

示例

public string ConnectionString { get;放;}

测试

public void TestConnectionString(){var c = new MyClass();c.ConnectionString = "值";Assert.Equal(c.ConnectionString, "value");}

我想我没有看到其中的价值.

解决方案

我建议你绝对应该这样做.

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

  • 你只是在测试编译器或框架"的说法有点像稻草人,恕我直言;当您测试自动属性时,从调用者的角度来看,您正在做的是测试您班级的公共接口".调用者不知道这是否是具有框架生成的后备存储的自动属性,或者 getter/setter 中是否有一百万行复杂代码.因此,调用者正在测试属性隐含的契约——如果你把 X 放进盒子里,你以后可以取回 X.

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

  • 像这样的测试可能需要一分钟的时间来编写,所以它并不是很繁重;并且您可以轻松地创建一个 T4 模板,该模板将通过一些反思为您自动生成这些测试.我现在实际上正在开发这样一个工具来为我们的团队节省一些苦差

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

  • 您是否更愿意进行前期回归测试,以便在 FNG 执行以下操作时:

<小时>

//24-SEP-2013::FNG - 为 ConnectionString 放置支持字段,因为我们现在正在对其进行构造函数注入公共字符串 ConnectionString{{获取{返回_connectionString;} }{set {_connectionString="foo";} }//FNG:我稍后再改,我很着急}///剪断公共 MyDBClass(字符串连接字符串){连接字符串=连接字符串;}

<小时>

立即知道他们弄坏了什么东西?

如果上面的内容似乎是为一个简单的字符串属性而设计的,我个人曾见过这样一种情况,即有人认为自动属性被重构了,他们认为自己太聪明了,并想将其从实例成员更改为围绕 a 的包装器静态类成员(代表发生的数据库连接,更改的原因并不重要).

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

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

根据此线程上的各种对话,我想指出读写属性的测试非常简单:

[测试方法]public void PropertyFoo_StoresCorrectly(){var sut = new MyClass();sut.Foo = "你好";Assert.AreEqual("你好", sut.Foo, "哎呀...");}

您甚至可以按照 Mark Seeman 的 自动修复

我认为,如果你发现你有如此多的公共属性,以至于每一行都要写上 3 行这样的苦差事,那么你应该质疑你的设计;如果您依靠另一个测试来表明此属性存在问题,那么要么

  • 测试实际上是在测试这个属性,或者
  • 与输入上述代码相比,您将花费更多时间来验证其他测试是否失败,因为属性不正确(通过调试器等)
  • 如果其他测试可以让您立即判断该属性有问题,那么这不是单元测试!

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

/编辑

最终视情况而定"可能是真正的答案,但需要注意的是,最好的默认"倾向是始终这样做"的方法,但在知情的情况下采取的例外情况.

Should you Unit Test simple properties of a class, asserting that a value is set and retrieved? Or is that really just unit testing the language?

Example

public string ConnectionString { get; set; }

Test

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

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

I guess I don't see the value in that.

解决方案

I would suggest that you absolutely should.

  • What is an auto-property today may end up having a backing field put against it tomorrow, and not by you...

  • The argument that "you're just testing the compiler or the framework" is a bit of a strawman imho; what you're doing when you test an auto-property is, from the perspective of the caller, testing the public "interface" of your class. The caller has no idea if this is an auto property with a framework-generated backing store, or if there is a million lines of complex code in the getter/setter. Therefore the caller is testing the contract implied by the property - that if you put X into the box, you can get X back later on.

  • Therefore it behooves us to include a test since we are testing the behaviour of our own code and not the behaviour of the compiler.

  • A test like this takes maybe a minute to write, so it's not exactly burdensome; and you can easily enough create a T4 template that will auto-generate these tests for you with a bit of reflection. I'm actually working on such a tool at the moment to save our team some drudgery

  • If you're doing pure TDD then it forces you to stop for a moment and consider if having an auto public property is even the best thing to do (hint: it's often not!)

  • Wouldn't you rather have an up-front regression test so that when the FNG does something like this:


//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;
}


You instantly know that they broke something?

If the above seems contrived for a simple string property I have personally seen a situation where an auto-property was refactored by someone who thought they were being oh so clever and wanted to change it from an instance member to a wrapper around a static class member (representing a database connection as it happens, the resons for the change are not important).

Of course that same very clever person completely forgot to tell anyone else that they needed to call a magic function to initialise this static member.

This caused the application to compile and ship to a customer whereupon it promptly failed. Not a huge deal, but it cost several hours of support's time==money.... That muppet was me, by the way!

EDIT: as per various conversations on this thread, I wanted to point out that a test for a read-write property is ridiculously simple:

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

edit: And you can even do it in one line as per Mark Seeman's Autofixture

I would submit that if you find you have such a large number of public properties as to make writing 3 lines like the above a chore for each one, then you should be questioning your design; If you rely on another test to indicate a problem with this property then either

  • The test is actually testing this property, or
  • You will spend more time verifying that this other test is failing because the property is incorrect (via debugger, etc) than you would have spent typing in the above code
  • If some other test allows you to instantly tell that the property is at fault, it's not a unit test!

edit (again!): As pointed out in the comments, and rightly so, things like generated DTO models and the like are probably exceptions to the above because they are just dumb old buckets for shifting data somewhere else, plus since a tool created them, it's generally pointless to test them.

/EDIT

Ultimately "It depends" is probably the real answer, with the caveat that the best "default" disposition to be the "always do it" approach, with exceptions to that taken on an informed, case by case basis.

这篇关于你应该对简单的属性进行单元测试吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆