简体   繁体   English

如果项目具有100%的单元测试覆盖率,是否仍需要集成测试?

[英]If a project has 100% unit test coverage, are integration tests still needed?

If a project has 100% unit test coverage, are integration tests still needed? 如果项目具有100%的单元测试覆盖率,是否仍需要集成测试?

I have never worked on a project with 100% unit test coverage, but I'm wondering if your project obtains this (or in the 90%), was your experience that you still needed integration tests? 我从未参与过100%单元测试覆盖率的项目,但是我想知道你的项目是否获得了这个(或90%),你的体验是否还需要集成测试? (did you need less?) (你需要更少吗?)

I ask because integration tests seem to suck. 我问,因为集成测试似乎很糟糕。 They are often slow, fragile (break easily), opaque (when broken someone has to dive through all the layers to find out what is wrong) and are causing our project to slow way down... I'm beginning to think that having only unit tests (and perhaps a small handful of smoke tests) is the way to go. 它们通常是缓慢的,脆弱的(容易折断),不透明(当有人不得不潜入所有层以找出问题时),并且导致我们的项目放慢速度......我开始认为拥有只有单元测试(也许是一小部分烟雾测试)才是最佳选择。

In the long run, it seems like integration tests (in my experience) cost more than they save. 从长远来看,似乎集成测试(根据我的经验)比他们节省的成本更高。

Thanks for your consideration. 谢谢你的考虑。

Definitions 定义

I think it's important to define your terms before having this discussion. 我认为在讨论之前定义你的术语很重要。

Unit test tests a single unit in isolation. 单元测试单独测试单个单元。 For me, that's a class. 对我来说,那是一堂课。 A unit test will create an object, invoke a method, and check a result. 单元测试将创建一个对象,调用方法并检查结果。 It answers the question "does my code do what I intended it to do?" 它回答了“我的代码是否符合我的意图?”的问题。

Integration test tests the combination of two components in the system. 集成测试测试系统中两个组件的组合。 It is focused on the relationship between the components, not the components themselves. 它侧重于组件之间的关系,而不是组件本身。 It answers the question "do these components work together as intended". 它回答了“将这些组件按预期一起工作”的问题。

System test tests the whole software system. 系统测试测试整个软件系统。 It answers the question "does this software work as intended?" 它回答了“这个软件是否按预期工作?”的问题。

Acceptance test is an automated way for the customer answer the question "is this software what I think I want?". 验收测试是一种自动化的方式,让客户回答“这个软件我认为我想要的是什么?”。 It is a kind of system test. 这是一种系统测试。

Note that none of these tests answer questions like "is this software useful?" 请注意,这些测试都没有回答诸如“这个软件有用吗?”之类的问题。 or "is this software easy to use?". 或“这个软件易于使用吗?”。

All automated tests are limited by axiom " End-to-end is further than you think " - eventually a human has to sit down in front of a computer and look at your user interface. 所有自动化测试都受到公理的限制“ 端到端比你想象的更远 ” - 最终人类不得不坐在电脑前看着你的用户界面。

Comparisons 比较

Unit tests are faster and easier to write, faster to run, and easier to diagnose. 单元测试更快,更容易编写,运行更快,更容易诊断。 They don't depend on "external" elements like a file system or a database, so they are much simpler/faster/reliable. 它们不依赖于“外部”元素,如文件系统或数据库,因此它们更简单/更快/更可靠。 Most unit tests continue to work as you refactor (and good unit tests are the only way to refactor safely). 大多数单元测试在重构时继续工作(良好的单元测试是安全重构的唯一方法)。 They absolutely require that your code be decoupled , which is hard, unless you write the test first. 他们绝对要求你的代码解耦 ,这很难,除非你先写测试。 This combination of factors makes the Red/Green/Refactor sequence of TDD work so well. 这些因素的组合使得TDD的Red / Green / Refactor序列运行良好。

System tests are hard to write, because they have to go through so much setup to get to a specific situation that you want to test. 系统测试很难编写,因为它们必须经过如此多的设置才能达到您想要测试的特定情况。 They are brittle, because any change in the behavior of the software before can affect the sequence leading up to the situation you want to test, even if that behavior isn't relevant to the test. 它们很脆弱,因为之前软件行为的任何变化都会影响导致您要测试的情况的顺序,即使该行为与测试无关。 They are dramatically slower than unit tests for similar reasons. 出于类似的原因,它们比单元测试慢得多。 Failures can be very difficult to diagnose, both because it can take a long time to get to the point of failure, and because so much software is involved in the failure. 故障可能非常难以诊断,因为它可能需要很长时间才能到达故障点,并且因为故障涉及太多软件。 In some software, system tests are very difficult to automate. 在某些软件中,系统测试很难自动化。

Integration tests sit in between: they are easier to write, run, and diagnose than system tests, but with broader coverage than unit tests. 集成测试介于两者之间:它们比系统测试更容易编写,运行和诊断,但覆盖范围比单元测试更广。

Recommendation 建议

Use a combination of testing strategies to balance the costs and values of each. 使用测试策略的组合来平衡每个的成本和价值。

Yes. 是。

Even if all "units" do what they are supposed to do, it is no guarantee that the complete system works as designed. 即使所有“单位”都做他们应该做的事情,也不能保证整个系统按设计工作。

Yes, besides there are a few different types of code coverage 是的,除了有几种不同类型的代码覆盖

from wiki: 来自维基:

  • Function coverage - Has each function in the program been executed? 功能覆盖 - 程序中的每个功能是否已执行?
  • Statement coverage - Has each line of the source code been executed? 声明覆盖 - 源代码的每一行都已执行?
  • Decision coverage (also known as Branch coverage) - Has each control structure (such as an if statement) evaluated both to true and false? 决策覆盖 (也称为分支覆盖) - 每个控制结构(例如if语句)是否都被评估为true和false?
  • Condition coverage - Has each boolean sub-expression evaluated both to true and false (this does not necessarily imply decision coverage)? 条件覆盖 - 每个布尔子表达式都被评估为true和false(这不一定意味着决策覆盖)?
  • Modified Condition/Decision Coverage (MC/DC) - Has every condition in a decision taken on all possible outcomes at least once? 修改的条件/决策覆盖范围(MC / DC) - 决策中的每个条件是否至少对所有可能的结果进行一次? Has each condition been shown to affect that decision outcome independently? 是否已证明每种情况都会独立影响该决策结果?
  • Path coverage - Has every possible route through a given part of the code been executed? 路径覆盖 - 是否已执行通过代码的给定部分的所有可能路径?
  • Entry/exit coverage - Has every possible call and return of the function been executed? 进入/退出覆盖范围 - 是否已执行所有可能的呼叫和返回功能?

Path coverage for example, just because every method has been called, doesn't mean that errors wont occur if you call various methods in a given order. 例如,路径覆盖,仅因为已调用每个方法,并不意味着如果您按给定顺序调用各种方法,则不会发生错误。

I've not really seen an answer that covers these considerations. 我还没有真正看到涵盖这些考虑因素的答案。 Now, I'm speaking from a holistic systems perspective, not form a SW development perspective, but... Integration is basically the process of combining lower level products into a higher level product. 现在,我从整体系统的角度讲,不是形成SW发展的视角,而是......整合基本上是将低级产品组合成更高级别产品的过程。 Each level has its own set of requirements to comply with. 每个级别都有自己的要求,以符合要求。 Although it is possible that some requirements are the same, the overall requirements set will be different for different levels. 尽管某些要求可能相同,但不同级别的总体要求集将有所不同。 This means that test objectives are different at different levels. 这意味着测试目标在不同级别上是不同的。 Also, the environment of the environment of the higher level product tends to be different from that of the lower level product (eg SW module testing may occur on a desktop environment, whereas a complete loadable SW item may be tested when loaded in its HW component). 此外,较高级别产品的环境环境往往与较低级别产品的环境不同(例如,SW模块测试可能发生在桌面环境中,而完整的可加载SW项目可能在加载到其HW组件中时进行测试)。 Furthermore, lower level component developers may not have the same understanding of the `requirements and design as the higher level product developers, so integration testing also validates to a certain extend the lower level product development. 此外,较低级别的组件开发人员可能对更高级别的产品开发人员的需求和设计没有相同的理解,因此集成测试也在一定程度上验证了较低级别的产品开发。

First, 100% unit test coverage is not enough even at unit testing level: you cover only 100% of the instructions of your code. 首先,即使在单元测试级别,100%的单元测试覆盖率也是不够的:您只能覆盖代码的100%指令。 What about paths in your code? 你的代码中的路径怎么样? What about input or output domains? 输入或输出域怎么样?

Second, you don't know whether output from a sender unit is compatible with input from its receiver unit. 其次,您不知道发送方单元的输出是否与其接收方单元的输入兼容。 This is the purpose of integration testing. 这是集成测试的目的。

Finally, unit testing may be performed on a different environment than production. 最后,可以在与生产不同的环境中执行单元测试。 Integration testing may reveal discrepancies. 集成测试可能会发现差异。

You can only prove the presence of a bug using tests/coverage, but you can never prove that the code is bug-free using tests/coverage. 您只能使用测试/覆盖证明存在错误,但您永远无法使用测试/覆盖证明该代码没有错误。 This fact indicates the boundaries of testing/coverage. 这一事实表明了测试/覆盖的界限。 This is the same in mathematics, you can disprove a theorem by finding a counter example, but you can never prove a theorem by not finding a counter example. 这在数学中是相同的,你可以通过找到一个反例来反驳一个定理,但你永远不能通过找不到反例来证明一个定理。 So testing and coverage are only a substitute for correctness proofs, which are so difficult to do that they are almost never used. 因此,测试和覆盖仅仅是正确性证明的替代品,这些证据难以完成,因此几乎从未使用过。 Testing and coverage can improve quality of the code, but there is no guarantee. 测试和覆盖可以提高代码的质量,但不能保证。 It remains a craft an not a science. 它仍然是一门工艺而非科学。

Unit tests are different from integration tests. 单元测试与集成测试不同。

Just to make a point: if I have to choose, I would dump unit tests and go with integration tests. 只是为了说明一点:如果我必须选择,我会转储单元测试并进行集成测试。 Experience tells that unit tests help to ensure functionality and also find bugs early in the development cycle. 经验告诉我们,单元测试有助于确保功能,并在开发周期的早期发现错误。

Integration testing is done with product looking close to what it would look to end users. 集成测试是在产品看起来与最终用户看起来很接近的情况下完成的。 That is important too. 这也很重要。

Unit tests are generally all about testing your class in isolation. 单元测试通常都是关于单独测试你的类。 They should be designed to ensure that given specific inputs your class exhibits predictable and expected behaviors. 它们应该被设计为确保给定特定输入您的类表现出可预测和预期的行为。

Integration tests are generally all about testing your classes in combinations with each other and with "outside" programs using those classes. 集成测试通常都是关于彼此组合测试您的类以及使用这些类的“外部”程序。 They should focus on ensuring that when the overall product uses your classes it is doing so in the correct manner. 他们应该专注于确保当整个产品使用您的类时,它正以正确的方式这样做。

“不透明(当有人不得不潜入所有层次以找出问题所在时”) - 这正是集成测试完成的原因 - 否则这些不透明的问题会出现在生产环境中。

Yes because the functionality of your software depends on how it's different piece interact. 是的,因为您的软件功能取决于它的不同部分如何互动。 Unit Tests depend on you coming with the inputs and defining the expected output. 单元测试取决于您使用输入并定义预期输出。 Doing this doesn't guarantee that it will work with the rest of your system. 这样做并不能保证它可以与系统的其余部分一起使用。

Yes integration testing is a pain to deal with when you introduce code changes that deliberately changes the output. 是的,当您引入故意更改输出的代码更改时,集成测试很难处理。 With our software we minimize by this by focusing on comparing the save result of a integration test with a saved correct result. 通过我们的软件,我们通过专注于将集成测试的保存结果与保存的正确结果进行比较来最小化。

We have a tool that can use when we are sure that we are producing the correct results. 当我们确信我们正在产生正确的结果时,我们有一个工具可以使用。 It goes and loads up the old saved correct results and modifies them to work with the new setup. 它会加载旧的已保存的正确结果并修改它们以使用新的设置。

I routinely see all sorts of issues uncovered by good integration testing - especially if you can automate some of your integration testing. 我经常看到良好的集成测试发现的各种问题 - 特别是如果你可以自动化一些集成测试。

Unit tests are great, but you can accomplish 100% code coverage without 100% relevancy in your unit tests. 单元测试很棒,但您可以在单元测试中实现100%的代码覆盖率,而不会有100%的相关性。 You're really trying to test different things, right? 你真的想尝试不同的东西,对吧? In unit tests, you're looking for edge cases for a specific function, usually, whereas integration testing is going to show you problems at a higher level as all these functions interact. 在单元测试中,您通常会查找特定函数的边缘情况,而集成测试会在所有这些函数交互时向您显示更高级别的问题。

If you build an API into your software, you can use this for automated integration testing - I've gotten a lot of mileage out of this in the past. 如果您在软件中构建API,则可以将其用于自动化集成测试 - 过去我已经获得了很多好处。 I don't know that I'd go as far as to say that I'd dump unit tests in favor of integration tests, but when they're done right, they're a really powerful addition. 我不知道我会说我倾向于单元测试以支持集成测试,但是当它们做得正确时,它们是一个非常强大的补充。

This exact question was basically just asked a day ago. 这个确切的问题基本上只是前一天才被问到。 See this question for lots of the errors you could run into even with 100% code coverage. 查看此问题 ,即使有100%的代码覆盖率,您也可能遇到很多错误。

It doesn't look like it was mentioned here, but you can never actually have 100% unit test coverage (if you have a database involved). 它看起来并不像这里提到的那样,但你实际上永远不会有100%的单元测试覆盖率(如果你有一个数据库)。 The moment you write a unit test for database connectivity and CRUD operations, you've just created an integration test. 在为数据库连接和CRUD操作编写单元测试的那一刻,您刚刚创建了一个集成测试。 The reason is because your test now has a dependency outside of the individual units of work. 原因是因为您的测试现在具有独立于各个工作单元之外的依赖性。 The projects I've worked on, and the developers I've spoken with, have always indicated that the remaining 10% is the DAO or service layer. 我所参与的项目以及我与之交谈过的开发人员一直表示剩余的10%是DAO或服务层。 The best way to test that is with integration tests and a mock (in-memory) database. 测试的最佳方法是使用集成测试和模拟(内存)数据库。 I've seen attempts to mock connections in order to unit test the DAO, but I don't really see the point -- your DAO is just a way to serialize raw data from one format to another, and your manager or delegate will decide how to manipulate it. 我已经看到尝试模拟连接以便对DAO进行单元测试,但我并没有真正看到这一点 - 您的DAO只是一种将原始数据从一种格式序列化到另一种格式的方式,您的经理或代表将决定如何操纵它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM