进行单元测试时,100%的代码覆盖率真的很好吗? [英] Is 100% code coverage a really good thing when doing unit tests?

查看:237
本文介绍了进行单元测试时,100%的代码覆盖率真的很好吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我总是认识到,使用单元测试进行最大代码覆盖是 。我也听到微软等大公司的开发人员说他们写的测试代码比可执行代码本身更多。



现在,真的很棒吗? b $ b

例如,假设我有一个方法 DisplayBooks(),它从数据库中填充图书列表。产品要求说明,如果店内有超过一百本图书,则必须显示只有一百本。



所以,在TDD


  1. 我将开始进行单元测试 BooksLimit()将保存在数据库中的两百本书中,调用 DisplayBooks(),然后执行 Assert.AreEqual(100,DisplayedBooks.Count)

  2. 然后我会测试它是否失败,

  3. 然后我会更改 DisplayBooks()通过将结果限制设置为100,而

  4. 最后,我将重新运行测试以查看是否成功。

嗯,直接进入第三步是不是更容易,直到不要使 BooksLimit()单元测试?而且不是更敏捷,当需求从100到200书限制变化时,只能更改一个字符,而不是更改测试,运行测试以检查它是否失败,更改代码并再次运行测试以检查它是否成功?



注意:让我们假设代码是完全记录的。否则有人会说,他们是对的,做全面的单元测试将有助于理解缺少文档的代码。事实上,使用 BooksLimit()单元测试将非常清楚地显示,显示的书籍数量最多,最大数量为100.进入非 - 单元测试代码将会更加困难,因为这样的限制可以通过(int bookIndex = 0; bookIndex <100; ... 或 foreach ... if(count> = 100)break;

解决方案


嗯,直接进入第三步是不是更容易,而且根本不会做BooksLimit()单元测试?


是...如果您不花时间编写测试,您将花费更少的时间编写测试。您的项目可能会整体上持续,因为您'调试时间很长,但也许这对您的经理来说更容易解释:如果是这样的事情就能找到新的工作!测试是提高您对软件的信心的关键。



Unittestin当你有很多代码时,g给出最大的价值。使用几个类进行简单的家庭作业调试很容易,无需单元测试。一旦你走出世界,你正在使用数百万行的代码库 - 你会需要它。你根本不能单步调试你的调试器。你根本无法理解一切。你需要知道你所依赖的课程。你需要知道有人说我要做这个改变,因为我需要这个行为,但是他们忘记了依赖于这种行为的其他二百种用途。



关于维护更难:我不能充分利用这一点。



如果你是唯一一个曾经在你的项目上工作的人,那么是的,你可能会认为。但那是疯狂的谈话!尝试加快在30k线路项目的速度,没有单位测试。尝试添加需要对代码进行重大更改而不进行单元测试的功能。没有信心,你没有违反其他工程师的隐含假设。对于维护者(或现有项目的新开发人员),单位测试是关键。我已经倾向于单位测试文件,行为,假设,告诉我什么时候我打破了一些东西(我认为是无关的)。有时一个写得不好的API书面测试不好,可能是一场噩梦的改变,因为测试吸引了你所有的时间。最终,你将要重构这个代码并解决这个问题,但你的用户也会感谢你,因为你的API会更容易使用。



关于覆盖的说明:



对我来说,这不是100%的测试覆盖率。 100%的覆盖率找不到所有的错误,考虑一个功能,两个如果语句:

  //将返回小于等于3的数字
int Bar(bool cond1,bool cond2){
int b;
if(cond1){
b ++;
} else {
b + = 2;
}

if(cond2){
b + = 2;
} else {
b ++;
}
}

现在考虑我写一个测试: p>

  EXPECT_EQ(3,Bar(true,true)); 
EXPECT_EQ(3,Bar(false,false));

这是100%的覆盖率。这也是一个不符合合约的功能 - Bar(false,true); 失败,因为它返回4.所以完全覆盖不是最终目标。



老实说,我会跳过 BooksLimit()的测试。它返回一个常量,所以编写它们可能不值得(当编写 DisplayBooks()时)应该进行测试。当有人决定(不正确地)从货架尺寸计算限制时,我可能会感到难过,不再满足我们的要求。以前我被不值得测试烧了。去年我写了一些我对同事说的代码:这个类大部分是数据,不需要测试。它有一个方法。它有一个错误。它去了生产。它在半夜给我们打了电话。我感到愚蠢所以我写了测试。然后我长时间思考了什么代码构成不值得测试。没有多少。



所以,是的,你可以跳过一些测试。 100%的测试覆盖很好,但并不奇怪,您的软件是完美的。这一切都归功于面对变化的信心。



如果我把 class A class B class C 在一起,我发现不起作用,我想花时间调试三个?不,我想知道, A B 已经通过单位测试达到了他们的合同和我的新代码 class C 可能已损坏。所以我单位测试。如果我不是单元测试,我怎么知道它是坏的?点击一些按钮并尝试新的代码?这很好,但还不够。一旦您的程序升级,就无法重新运行所有手动测试,以检查一切正常。这就是为什么单元测试通常会自动运行测试的原因。告诉我通过或失败,不要告诉我输出是...。



可以,再去写一些更多的测试...


I always learned that doing maximum code coverage with unit tests is good. I also hear developers from big companies such as Microsoft saying that they write more lines of testing code than the executable code itself.

Now, is it really great? Doesn't it seem sometimes like a complete loss of time which has an only effect to making maintenance more difficult?

For example, let's say I have a method DisplayBooks() which populates a list of books from a database. The product requirements tell that if there are more than one hundred books in the store, only one hundred must be displayed.

So, with TDD,

  1. I will start by making an unit test BooksLimit() which will save two hundred books in the database, call DisplayBooks(), and do an Assert.AreEqual(100, DisplayedBooks.Count).
  2. Then I will test if it fails,
  3. Then I'll change DisplayBooks() by setting the limit of results to 100, and
  4. Finally I will rerun the test to see if it succeeds.

Well, isn't it much more easier to go directly to the third step, and do never make BooksLimit() unit test at all? And isn't it more Agile, when requirements will change from 100 to 200 books limit, to change only one character, instead of changing tests, running tests to check if it fails, changing code and running tests again to check if it succeeds?

Note: lets assume that the code is fully documented. Otherwise, some may say, and they would be right, that doing full unit tests will help to understand code which lacks documentation. In fact, having a BooksLimit() unit test will show very clearly that there is a maximum number of books to display, and that this maximum number is 100. Stepping into the non-unit-tests code would be much more difficult, since such limit may be implemented though for (int bookIndex = 0; bookIndex < 100; ... or foreach ... if (count >= 100) break;.

解决方案

Well, isn't it much more easier to go directly to the third step, and do never make BooksLimit() unit test at all?

Yes... If you don't spend any time writing tests, you'll spend less time writing tests. Your project might take longer overall, because you'll spend a lot of time debugging, but maybe that's easier to explain to your manager? If that's the case... get a new job! Testing is crucial to improving your confidence in your software.

Unittesting gives the most value when you have a lot of code. It's easy to debug a simple homework assignment using a few classes without unittesting. Once you get out in the world, and you're working in codebases of millions of lines - you're gonna need it. You simply can't single step your debugger through everything. You simply can't understand everything. You need to know that the classes you're depending on work. You need to know if someone says "I'm just gonna make this change to the behavior... because I need it", but they've forgotten that there's two hundred other uses that depend on that behavior. Unittesting helps prevent that.

With regard to making maintenance harder: NO WAY! I can't capitalize that enough.

If you're the only person that ever worked on your project, then yes, you might think that. But that's crazy talk! Try to get up to speed on a 30k line project without unittests. Try to add features that require significant changes to code without unittests. There's no confidence that you're not breaking implicit assumptions made by the other engineers. For a maintainer (or new developer on an existing project) unittests are key. I've leaned on unittests for documentation, for behavior, for assumptions, for telling me when I've broken something (that I thought was unrelated). Sometimes a poorly written API has poorly written tests and can be a nightmare to change, because the tests suck up all your time. Eventually you're going to want to refactor this code and fix that, but your users will thank you for that too - your API will be far easier to use because of it.

A note on coverage:

To me, it's not about 100% test coverage. 100% coverage doesn't find all the bugs, consider a function with two if statements:

// Will return a number less than or equal to 3
int Bar(bool cond1, bool cond2) {
  int b;
  if (cond1) {
    b++;
  } else {
    b+=2;
  }

  if (cond2) {
    b+=2;
  } else {
    b++;
  }
}

Now consider I write a test that tests:

EXPECT_EQ(3, Bar(true, true));
EXPECT_EQ(3, Bar(false, false));

That's 100% coverage. That's also a function that doesn't meet the contract - Bar(false, true); fails, because it returns 4. So "complete coverage" is not the end goal.

Honestly, I would skip tests for BooksLimit(). It returns a constant, so it probably isn't worth the time to write them (and it should be tested when writing DisplayBooks()). I might be sad when someone decides to (incorrectly) calculate that limit from the shelf size, and it no longer satisfies our requirements. I've been burned by "not worth testing" before. Last year I wrote some code that I said to my coworker: "This class is mostly data, it doesn't need to be tested". It had a method. It had a bug. It went to production. It paged us in the middle of the night. I felt stupid. So I wrote the tests. And then I pondered long and hard about what code constitutes "not worth testing". There isn't much.

So, yes, you can skip some tests. 100% test coverage is great, but it doesn't magically mean your software is perfect. It all comes down to confidence in the face of change.

If I put class A, class B and class C together, and I find something that doesn't work, do I want to spend time debugging all three? No. I want to know that A and B already met their contracts (via unittests) and my new code in class C is probably broken. So I unittest it. How do I even know it's broken, if I don't unittest? By clicking some buttons and trying the new code? That's good, but not sufficient. Once your program scales up, it'll be impossible to rerun all your manual tests to check that everything works right. That's why people who unittest usually automate running their tests too. Tell me "Pass" or "Fail", don't tell me "the output is ...".

OK, gonna go write some more tests...

这篇关于进行单元测试时,100%的代码覆盖率真的很好吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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