为什么使用集成测试而不是单元测试是一个坏主意?
让我从定义开始:
单元测试是一种软件验证和确认方法,程序员在其中测试源代码的各个单元是否适合使用
集成测试是以下活动:软件测试,将各个软件模块组合起来并作为一个整体进行测试。
尽管它们有不同的用途,但这些术语经常被混淆。开发人员将自动化集成测试称为单元测试。还有一些人争论哪一个更好,这在我看来根本是一个错误的问题。
我想请开发社区分享他们对为什么自动化集成测试不能取代经典单元测试的看法。
以下是我自己的观察:
- 集成测试不能与 TDD 方法一起使用
- 集成测试很慢并且不能经常执行
- 在大多数情况下,集成测试并不能表明问题的根源
- 使用集成测试创建测试环境会更加
- 困难更难以确保高覆盖率(例如模拟特殊情况、意外故障等)
- 集成测试不能与 基于交互的测试
- 集成测试进一步推动发现缺陷的时刻(来自paxdiablo)
编辑:再次澄清:问题不在于是否使用集成测试还是单元测试,而不在于哪一个更有用。基本上,我想向只编写集成测试并将其视为单元测试的开发团队收集参数。 任何涉及不同层组件的测试都被视为集成测试。这是与以隔离为主要目标的单元测试进行比较。
谢谢你, 安德烈
Let me start from definition:
Unit Test is a software verification and validation method in which a programmer tests if individual units of source code are fit for use
Integration testing is the activity of software testing in which individual software modules are combined and tested as a group.
Although they serve different purposes very often these terms are mixed up. Developers refer to automated integration tests as unit tests. Also some argue which one is better which seems to me as a wrong question at all.
I would like to ask development community to share their opinions on why automated integration tests cannot replace classic unit tests.
Here are my own observations:
- Integration tests can not be used with TDD approach
- Integration tests are slow and can not be executed very often
- In most cases integration tests do not indicate the source of the problem
- it's more difficult to create test environment with integration tests
- it's more difficult to ensure high coverage (e.g. simulating special cases, unexpected failures etc)
- Integration tests can not be used with Interaction based testing
- Integration tests move moment of discovering defect further (from paxdiablo)
EDIT: Just to clarify once again: the question is not about whether to use integration or unit testing and not about which one is more useful. Basically I want to collect arguments to the development teams which write ONLY integration tests and consider them as unit tests.
Any test which involve components from different layers is considered as integration test. This is to compare to unit test where isolation is the main goal.
Thank you,
Andrey
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
集成测试会告诉您它是否有效。单元测试告诉您什么不起作用。只要一切正常,您“不需要”单元测试 - 但一旦出现问题,让单元测试直接指出问题是非常好的。正如你所说,它们有不同的目的;两者兼得就好。
直接解决您的主题:集成测试不是问题,不是问题。使用它们而不是单元测试是。
Integration tests tell you whether it's working. Unit tests tell you what isn't working. So long as everything is working, you "don't need" the unit tests - but once something is wrong, it's very nice to have the unit test point you directly to the problem. As you say, they serve different purposes; it's good to have both.
To directly address your subject: integration tests aren't a problem, aren't the problem. Using them instead of unit tests is.
我发现集成测试明显优于单元测试。如果我对我的代码进行单元测试,我只是测试它的功能与我对它应该做什么的理解。这只捕获实现错误。但往往更大的问题是理解错误。集成测试抓住了两者。
此外,成本也存在巨大差异;如果您大量使用单元测试,它们的重量超过所有其他代码的总和并不少见。它们需要维护,就像代码的其余部分一样。集成测试要便宜得多——而且在大多数情况下,您无论如何都已经需要它们了。
在极少数情况下,可能需要使用单元测试,例如对于内部错误处理路径,如果系统的其余部分正常工作,则无法触发这些路径,但大多数时候,单独的集成测试可以提供更好的结果成本更低。
I find integration tests markedly superior to unit tests. If I unit test my code, I'm only testing what it does versus my understanding of what it should do. That only catches implementation errors. But often a much bigger problem is errors of understanding. Integration tests catch both.
In addition, there is a dramatic cost difference; if you're making intensive use of unit tests, it's not uncommon for them to outweigh all the rest of your code put together. And they need to be maintained, just like the rest of the code does. Integration tests are vastly cheaper -- and in most cases, you already need them anyway.
There are rare cases where it might be necessary to use unit tests, e.g. for internal error handling paths that can't be triggered if the rest of the system is working correctly, but most of the time, integration tests alone give better results for far lower cost.
研究(a)表明,当您远离引入错误的位置时,修复错误的成本会变得更高。
例如,修复尚未推送到源代码控制的软件中的错误通常花费相对较少。这是你的时间,但时间不多,我保证(假设你擅长你的工作)。
将其与客户(或所有客户)发现该问题时修复所需的成本进行对比。许多级别的人员都参与其中,必须快速构建新软件并将其推向现场。
这就是极端的比较。但即使是单元测试和集成测试之间的差异也是显而易见的。单元测试失败的代码大多只影响单个开发人员(当然,除非其他开发人员/测试人员/等正在等待它)。然而,一旦您的代码参与集成测试,缺陷就会开始阻碍您团队中的其他人。
我们不会梦想用集成测试替换我们的单元测试,因为:
(a) 例如,参见http://slideshare.net/Vamsipothuri /defect-prevention,幻灯片 # 5,或在网上搜索
缺陷预防:降低成本并提高质量
。图表中的图表复制如下,以防在网上很难找到:There have been studies(a) that show that the cost of fixing a bug becomes higher as you move away from the point where the bug was introduced.
For example, it will generally cost you relatively little to fix a bug in software you haven't even pushed up to source control yet. It's your time and not much of it, I'd warrant (assuming you're any good at your job).
Contrast that with how much it costs to fix when the customer (or all your customers) find that problem. Many level of people get involved and new software has to be built in a hurry and pushed out to the field.
That's the extreme comparison. But even the difference between unit and integration tests can be apparent. Code that fails unit testing mostly affects only the single developer (unless other developers/testers/etc are waiting on it, of course). However, once your code becomes involved in integration testing, a defect can begin holding up other people on your team.
We wouldn't dream of replacing our unit tests with integration tests since:
(a) See, for example, http://slideshare.net/Vamsipothuri/defect-prevention, slide # 5, or search the net for
Defect prevention : Reducing costs and enhancing quality
. Th graph from the chart is duplicated below in case it ever becomes hard to find on the net:原因(没有集中注意力并且
孤立)。因此你需要更多
对失败进行调试。
场景太大,无法集成
在未进行单元测试时进行测试。
我主要进行单元测试和少 10 倍的集成测试(配置、查询)。
reasons (it is not focused and
isolated). Therefore you need more
debugging on failures.
scenarios are to big for integration
test when it is not unit tested.
Mostly I do unit tests and 10 times less integration tests (configuration, queries).
在许多情况下,两者都需要。就我而言,关于使用集成测试作为单元测试,您的观察是正确的,但这并不意味着集成测试没有价值或不需要,只是它们服务于不同的目的。人们同样可以认为单元测试不能取代集成测试,正是因为它们消除了对象之间的依赖关系,并且它们不运用真实的环境。两者都是正确的。
In many cases you need both. Your observations are right on track as far as I'm concerned with respect to using integration tests as unit tests, but they don't mean that integration tests are not valuable or needed, just that they serve a different purpose. One could equally argue that unit tests can't replace integration tests, precisely because they remove the dependencies between objects and they don't exercise the real environment. Both are correct.
这一切都是为了减少迭代时间。
通过单元测试,您可以编写一行代码并在一分钟左右的时间内验证它。对于集成测试,通常需要更长的时间(并且成本随着项目的增长而增加)。
两者显然都很有用,因为两者都能检测到对方无法检测到的问题。
OTOH,从“纯粹的”TDD 方法来看,单元测试不是测试,而是功能规范。集成测试,OTOH,实际上是在更传统的意义上进行“测试”。
It's all about reducing the iteration time.
With unit tests, you can write a line of code and verify it in a minute or so. With integration tests, it usually takes significantly longer (and the cost increases as the project grows).
Both are clearly useful, as both will detect issues that the other fails to detect.
OTOH, from a "pure" TDD approach, unit tests aren't tests, they're specifications of functionality. Integration tests, OTOH, really do "test" in the more traditional sense of the word.
集成测试通常在单元测试之后进行。我不确定测试未经测试的单元之间的交互有什么价值。
如果齿轮可能损坏,那么测试机器的齿轮如何一起转动就没有意义。
Integration testing generally happens after unit testing. I'm not sure what value there is in testing interactions between units that have not themselves been tested.
There's no sense in testing how the gears of a machine turn together if the gears might be broken.
两种类型的测试是不同的。在我看来,单元测试并不能替代集成测试。主要是因为集成测试通常是特定于上下文的。您很可能会遇到这样的情况:单元测试失败,而您的集成却没有失败,反之亦然。如果您在使用许多其他组件的类中实现了不正确的业务逻辑,您会希望您的集成测试突出显示这些逻辑,您的单元测试不会注意到这一点。我知道集成测试既快速又简单。我认为,每次对代码库进行更改时,您都会依赖单元测试,并且拥有一个绿色列表将使您更有信心,您没有破坏单个类级别的任何预期行为。单元测试为您提供了针对单个类是否执行其设计目的的测试。集成测试测试多个类一起工作是否完成您期望它们为特定协作实例执行的操作。这就是面向对象开发的整体思想:封装特定逻辑的各个类,从而允许重用。
The two types of tests are different. Unit tests, in my opinion are not a alternative to integration tests. Mainly because integration tests are usually context specific. You may well have a scenario where a unit test fails and your integration doesn't and vice versa. If you implement incorrect business logic in a class that utilizes many other components, you would want your integration tests to highlight these, your unit tests are oblivious to this.I understand that integration testing is quick and easy. I would argue you rely on your unit tests each time you make a change to your code-base and having a list of greens would give you more confidence that you have not broken any expected behavior at the individual class level. Unit tests give you a test against a single class is doing what it was designed to do. Integration tests test that a number of classes working together do what you expect them to do for that particular collaboration instance. That is the whole idea of OO development: individual classes that encapsulate particular logic, which allows for reuse.
我认为覆盖范围是主要问题。
对特定小组件(例如方法或最多一个类)的单元测试应该在每个合法场景中测试该组件(当然,一个抽象等价类,但应该涵盖每个主要类)。因此,此时应该捕获违反既定规范的更改。
在大多数情况下,集成仅使用每个子单元可能场景的子集,因此故障单元仍然有可能生成最初集成良好的程序。
由于您在下面指定的所有原因,通常很难实现集成测试的最大覆盖率。如果没有单元测试,那么在新场景中本质上运行该单元的更改很可能不会被捕获,并且可能会在集成测试中被遗漏。即使没有遗漏,查明问题也可能极其困难。
我不确定大多数开发人员是否将单元测试称为集成测试。我的印象是,大多数开发人员都了解这些差异,但这并不意味着他们也实践过。
I think coverage is the main issue.
A unit test of a specific small component such as a method or at most a class is supposed to test that component in every legal scenario (of course, one abstracts equivalence classes but every major one should be covered). As a result, a change that breaks the established specification should be caught at this point.
In most cases, an integration uses only a subset of the possible scenarios for each subunit, so it is possible for malfunctioning units to still produce a program that initially integrates well.
It is typically difficult to achieve maximal coverage on the integration testing for all the reasons you specified below. Without unit tests, it is more likely that a change to a unit that essentially operates it in a new scenario would not be caught and might be missed in the integration testing. Even if it is not missed, pinpointing the problem may be extremely difficult.
I am not sure that most developers refer to unit tests as integration tests. My impression is that most developers understand the differences, which does not mean they practice either.
编写单元测试是为了测试类上的方法。如果该类依赖于任何类型的外部资源或行为,您应该模拟它们,以确保您只测试您的单个类。单元测试中不应有外部资源。
集成测试是更高级别的粒度,正如您所说,您应该测试多个组件以检查它们是否按预期协同工作。大多数项目都需要集成测试和单元测试。但重要的是,将它们分开并理解它们之间的差异。
在我看来,单元测试对于人们来说更难掌握。它需要充分了解 OO 原则(基本上基于一级责任)。如果您能够单独测试所有类,那么您很可能拥有一个可维护、灵活且可扩展的设计良好的解决方案。
它们应该在几秒钟内完成,而不是几分钟或几小时。
A unit test is written to test a method on a class. If that class depends on any kind of external resource or behavior, you should mock them, to ensure you test just your single class. There should be no external resources in a unit test.
An integration test is a higher level of granularity, and as you stated, you should test multiple components to check if they work together as expected. You need both integration tests and unit tests for most projects. But it is important they are kept separate and the difference is understood.
Unit tests, in my opinion, are more difficult for people to grasp. It requires a good knowledge of OO principles (fundamentally based on one class one responsibility). If you are able to test all your classes in isolation, chances are you have a well design solution which is maintainable, flexible and extendable.
they should be done in a few seconds, not minutes or hours.
我认为两者都很有价值,而且谁都无法取代对方所做的工作。我确实看到很多集成测试伪装成单元测试,尽管它们具有依赖性并且需要很长时间才能运行。它们应该独立运行并作为持续集成系统的一部分。
集成测试确实经常发现单元测试没有发现的东西......
I think both are valuable and neither one can replace the other in the job they do. I do see a lot of integration tests masquerading as unit tests though having dependencies and taking a long time to run. They should function separately and as part of a continuous integration system.
Integration tests do often find things that unit tests do not though...
集成测试可让您检查应用程序的整个用例是否正常工作。
单元测试检查应用程序中的低级逻辑是否正确。
集成测试对于管理者来说更有用,可以让他们对项目的状态感到更安全(但对于开发人员也很有用!)。
单元测试对于编写和更改应用程序逻辑的开发人员更有用。
当然,同时使用它们可以达到最佳效果。
Integration tests let you check that whole use cases of your application work.
Unit tests check that low-level logic in your application is correct.
Integration tests are more useful for managers to feel safer about the state of the project (but useful for developers too!).
Unit tests are more useful for developers writing and changing application logic.
And of course, use them both to achieve best results.
(我认为)OP这里所说的集成测试更倾向于场景级别的测试。
但是我们如何在单位 -> 之间划清界限? 集成 -> 场景?
我经常看到的是开发人员编写一个功能,然后在单元测试时模拟该功能使用/消耗的所有其他代码,并且只测试他们自己的功能代码,因为他们认为其他人测试了它,所以应该没问题。这有助于代码覆盖率,但通常会损害应用程序。
理论上,单元测试的小隔离应该涵盖很多内容,因为所有内容都在其自己的范围内进行测试。但这样的测试是有缺陷的,并且无法看到完整的情况。
一个好的单元测试应该尝试尽可能少地模拟。例如,模拟 API 和持久性就是这样的。即使应用程序本身不使用 IOC(控制反转),也应该很容易启动一些对象进行测试,而无需进行模拟,如果从事该项目的每个开发人员都这样做,那么它会变得更加容易。 那么测试就有用了。此类测试具有集成特性,编写起来并不容易,但可以帮助您发现代码的设计缺陷。如果不容易测试,那么调整您的代码以使其易于测试。 (TDD)
优点
缺点
良好的集成测试将针对完整的端到端场景执行,甚至检查单元测试无法涵盖的持久性和 API,以便您可能知道在哪里查找首先当这些失败时。
优点:
缺点:
TLDR:两者都需要,但不能用另一个替换!问题是如何设计此类测试以充分利用两者。不仅仅是让他们向管理层展示良好的统计数据。
(I think) What is referred here by OP as integration tests are leaning more to scenario level tests.
But where do we draw the line between unit -> integration -> scenario?
What I often see is developers writing a feature and then when unit testing it mocking away every other piece of code this feature uses/consumes and only test their own feature-code because they think someone else tested that so it should be fine. This helps code coverage but can harm the application in general.
In theory the small isolation of Unit Test should cover a lot since everything is tested in its own scope. But such tests are flawed and do not see the complete picture.
A good Unit test should try to mock as least as possible. Mocking API and persistency would be something for example. Even if the application itself does not use IOC (Inversion Of Control) it should be easy to spin up some objects for a test without mocking if every developer working on the project does it as well it gets even easier. Then the test are useful. These kind of tests have an integration character to them aren't as easy to write but help you find design flaws of your code. If it is not easy to test then adapt your code to make it easy to test. (TDD)
Pros
Cons
A good integration test would be executed for complete end to end scenarios and even check persistency and APIs which the unit test could not cover so you might know where to look first when those fail.
Pros:
Cons:
TLDR: You need both you cant replace one with the other! The question is how to design such tests to get the best from both. And not just have them to show good statistics to the management.
“使用集成测试而不是单元测试”是一个坏主意,因为这意味着您不了解他们正在测试不同的东西,当然还有通过和失败测试会给你不同的信息。当他们从两边接近时,它们构成了某种阴阳测试。
集成测试采用模拟用户如何与应用程序交互的方法。这些将减少对手动测试的需求,并且通过测试将告诉您您的应用程序适合在多个平台上运行。失败的测试会告诉您某些东西已损坏,但通常不会为您提供有关底层代码出现问题的大量信息。
单元测试应该侧重于确保函数的输入和输出在所有情况下都符合您的预期。通过单元测试可能意味着您的功能按照规范运行(假设您对所有情况进行了测试)。然而,所有功能单独正常运行并不一定意味着部署后一切都会完美运行。失败的单元测试将为您提供有关失败原因的详细、具体信息,理论上这应该使调试更容易。
最后,我相信单元测试和集成测试的结合将产生最快、最无错误的软件。你可以选择使用其中之一而不是另一个,但我避免使用“而不是”这个短语。
It is a bad idea to "use integration tests instead of unit tests" because it means you aren't appreciating that they are testing different things, and of course passing and failing tests will give you different information. They make up sort of a ying and yang of testing as they approach it from either side.
Integration tests take an approach that simulates how a user would interact with the application. These will cut down on the need for as much manual testing, and passing tests will can tell you that you app is good to go on multiple platforms. A failing test will tell you that something is broken but often doesn't give you a whole lot of information about what's wrong with the underlying code.
Unit tests should be focusing on making sure the inputs and outputs of your function are what you expect them to be in all cases. Passing units tests can mean that your functions are working according to spec (assuming you have tests for all situations). However, all your functions working properly in isolation doesn't necessarily mean that everything will work perfectly when it's deployed. A failing unit test will give you detailed, specific information about why it's failing which should in theory make it easier to debug.
In the end I believe a combination of both unit and integration tests will yield the quickest a most bug-free software. You could choose to use one and not the other, but I avoid using the phrase "instead of".
我如何看待集成测试和集成测试单元测试:
单元测试:用低级细节单独测试小事情,包括但不限于“方法条件”、检查、循环、默认、计算等。
集成测试: 测试更广泛的范围,涉及多个组件,这可能会影响其他事物结合在一起时的行为。集成测试应涵盖端到端集成和集成测试。行为。集成测试的目的应该是证明系统/组件集成在一起时可以正常工作。
How I see integration testing & unit testing:
Unit Testing: Test small things in isolation with low level details including but not limited to 'method conditions', checks, loops, defaulting, calculations etc.
Integration testing: Test wider scope which involves number of components, which can impact the behaviour of other things when married together. Integration tests should cover end to end integration & behaviours. The purpose of integration tests should be to prove systems/components work fine when integrated together.