我知道所谓的单元测试和集成测试的教科书定义。我好奇的是什么时候该写单元测试了……我将写它们来覆盖尽可能多的类集。

例如,如果我有一个Word类,我将为Word类编写一些单元测试。然后,我开始编写我的Sentence类,当它需要与Word类交互时,我经常会编写单元测试,这样它们就可以同时测试Sentence和Word……至少在他们相互作用的地方。

这些测试本质上变成集成测试了吗?因为它们现在测试这两个类的集成,还是仅仅是一个跨越两个类的单元测试?

一般来说,由于这条不确定的界线,我很少实际编写集成测试……或者我是否使用成品来查看所有部件是否正常工作,即实际的集成测试,即使它们是手动的,并且很少在每个单独的功能范围之外重复?

我是否误解了集成测试,或者集成测试和单元测试之间真的只有很小的区别?


当前回答

A little bit academic this question, isn't it? ;-) My point of view: For me an integration test is the test of the whole part, not if two parts out of ten are going together. Our integration test shows, if the master build (containing 40 projects) will succeed. For the projects we have tons of unit tests. The most important thing concerning unit tests for me is, that one unit test must not be dependent on another unit test. So for me both test you describe above are unit tests, if they are independent. For integration tests this need not to be important.

其他回答

在我看来,答案是“为什么这很重要?”

是不是因为您只做单元测试而不做集成测试?反之亦然?当然不是,你应该尝试两者兼得。

是因为单元测试需要快速、隔离、可重复、自我验证和及时,而集成测试不需要吗?当然不是,所有的测试都应该是这样。

这是因为您在单元测试中使用模拟,而在集成测试中不使用它们吗?当然不是。这意味着,如果我有一个有用的集成测试,我不允许为某些部分添加模拟,担心我将不得不将我的测试重命名为“单元测试”或将其交给另一个程序员来处理。

是不是因为单元测试测试一个单元,而集成测试测试许多单元?当然不是。这有什么实际意义呢?关于测试范围的理论讨论在实践中无论如何都是行不通的,因为术语“单元”完全依赖于上下文。在类级别上,单元可能是一个方法。在程序集级别上,单元可能是类,而在服务级别上,单元可能是组件。 甚至类也会使用其他类,那么哪个是单位呢?

这无关紧要。

测试很重要,F.I.R.S.T也很重要,对定义吹毛求疵是浪费时间,只会让测试新手感到困惑。

我的10位:D

我总是被告知单元测试是对单个组件的测试——应该充分地进行测试。现在,这往往有很多层次,因为大多数组件是由较小的部件组成的。对我来说,单元是系统的功能部分。所以它必须提供一些有价值的东西(例如,不是字符串解析的方法,而是HtmlSanitizer)。

集成测试是下一步,它采用一个或多个组件,并确保它们按照应有的方式一起工作。然后,你是在担心组件如何单独工作的复杂,但当你输入html到你的htmledcontrol,它以某种神奇的方式知道它是否有效。

这是一条真正可移动的线。我宁愿更专注于让该死的代码完全停止工作^_^

这些测试本质上变成集成测试了吗?因为它们现在测试的是这两个类的集成?或者它只是一个跨越2个类的单元测试?

我认为是和是。跨越2个类的单元测试变成了集成测试。

您可以通过使用mock实现(MockWord类)测试Sentence类来避免这种情况,当系统的这些部分足够大,可以由不同的开发人员实现时,这一点非常重要。在这种情况下,Word是单独的单元测试,句子是在MockWord的帮助下进行单元测试,然后句子是用Word进行集成测试。

以下是真实差异的例子 1) 1,000,000个元素的数组很容易进行单元测试,工作良好。 2) BubbleSort很容易在10个元素的模拟数组上进行单元测试,而且工作得很好 3)集成测试表明有些东西不是很好。

如果这些部分是由一个人开发的,在单元测试BubbleSoft时很可能会发现问题,因为开发人员已经有了真实的数组,他不需要模拟实现。

类比的简单解释

上面的例子已经很好了,我就不再重复了。所以我会用例子来帮助你们理解。

集成测试

集成测试检查是否一切都在一起工作。想象一下手表上的一系列齿轮一起工作。一个综合测试是:手表是否显示正确的时间?它还能在3天内显示正确的时间吗?

它只告诉你整个部件是否正常工作。如果它失败了:它不会告诉你它到底在哪里失败。

单元测试

这些都是非常具体的测试类型。它们告诉你一件具体的事情是有效还是失败。这种类型的测试的关键是,它只测试一个特定的东西,同时假设其他一切都正常工作。这是关键。

例子: 让我们用一个例子来详细说明这一点:

Let’s take a car as an example. Integration test for a car: e.g. does the car drive to Woop Woop and back? If it does this, you can safely say that a car is working from an overall view point. It is an integration test. If it fails you have no idea where it is actually failing: is it the radiator, transmission, engine, or carburettor? You have no idea. It could be anything. Unit test for a car: Is the engine is working? This tests assumes that everything else in the car is working just fine. That way, if this particular unit test fails: you can be very confident that the problem lies in the engine – so you can quickly isolate and fix the problem.

使用存根

假设您的汽车集成测试失败。它不能成功地开到埃丘卡。问题出在哪里? 现在让我们假设你的发动机使用一个特殊的燃油喷射系统,这个发动机单元测试也失败了。换句话说,集成测试和发动机单元测试都失败了。那么问题在哪里呢?(给自己10秒钟的时间来回答。) 是发动机出了问题,还是燃油喷射系统出了问题?

你看到问题了吗?你不知道什么是失败。如果你使用不同的外部依赖关系,那么这10个依赖关系中的每一个都可能导致问题——你不知道从哪里开始。这就是为什么单元测试使用存根来假设其他一切都正常工作。

你测试的性质

模块X的单元测试是仅在模块X中预期(并检查)问题的测试。

许多模块的集成测试是一种预期由模块之间的合作产生的问题的测试,这样单独使用单元测试就很难发现这些问题。

从以下方面考虑测试的性质:

Risk reduction: That's what tests are for. Only a combination of unit tests and integration tests can give you full risk reduction, because on the one hand unit tests can inherently not test the proper interaction between modules and on the other hand integration tests can exercise the functionality of a non-trivial module only to a small degree. Test writing effort: Integration tests can save effort because you may then not need to write stubs/fakes/mocks. But unit tests can save effort, too, when implementing (and maintaining!) those stubs/fakes/mocks happens to be easier than configuring the test setup without them. Test execution delay: Integration tests involving heavyweight operations (such as access to external systems like DBs or remote servers) tend to be slow(er). This means unit tests can be executed far more frequently, which reduces debugging effort if anything fails, because you have a better idea what you have changed in the meantime. This becomes particularly important if you use test-driven development (TDD). Debugging effort: If an integration test fails, but none of the unit tests does, this can be very inconvenient, because there is so much code involved that may contain the problem. This is not a big problem if you have previously changed only a few lines -- but as integration tests run slowly, you perhaps did not run them in such short intervals...

记住,集成测试仍然可能存根/伪造/模拟它的一些依赖项。 这在单元测试和系统测试(最全面的集成测试,测试所有系统)之间提供了大量的中间地带。

务实的方法使用两者

因此,一种务实的方法是:尽可能灵活地依赖集成测试,在风险太大或不方便的地方使用单元测试。 这种思维方式可能比单元测试和集成测试的一些教条主义区分更有用。