集成和unit testing有什么区别?

我知道所谓的unit testing和集成testing的教科书定义。 我很好奇的是什么时候该编写unit testing的时候了……我会把它们写成尽可能多的类。

例如,如果我有一个Word类,我将为Word类编写一些unit testing。 然后,我开始写我的Sentence类,当它需要与Word类交互时,我会经常写我的unit testing,以便他们testingSentenceWord …至less在他们互动的地方。

有这些testing基本上成为集成testing,因为他们现在testing这两个类的集成,还是只是一个跨越两个类的unit testing?

一般来说,由于这个不确定的线,我很less会真正写集成testing…或者是我使用完成的产品来看看所有的部分工作正确的实际集成testing,即使他们是手动的,很less重复超出范围每个人的特征?

我是否误解了集成testing,还是在集成和unit testing之间真的只有很小的差别?


编辑

感谢所有人的回应! 我认为,从各种各样的答案中可以明显看出,unit testing和集成testing之间的界限绝对是一个模糊的线条,也许有点迂腐,试图找出哪些是真正的焦点应该停留在代码上(谢谢@Rob Cooper )。 另外,抱歉,我不会接受任何答案,因为太多太好了,而且看起来真的很主观。

对我来说,关键的区别在于, 集成testing揭示了一个特性是否正在工作或者被破坏,因为它们会在接近现实的情况下强调代码。 他们调用一个或多个软件方法或function,并testing它们是否按预期行事。

相反,testing单一方法的unit testing依赖于其他软件正常工作的错误假设,因为它明确地嘲笑每个依赖关系。

因此,当实现某些function的方法的unit testing是绿色时,并不意味着该function正在工作。

假设你有一个这样的方法

 public SomeResults DoSomething(someInput) { var someResult = [Do your job with someInput]; Log.TrackTheFactYouDidYourJob(); return someResults; } 

DoSomething对您的客户来说非常重要:这是一个function,唯一重要的事情。 这就是为什么你通常写一个黄瓜规范声明:你想validation沟通function是否工作。

 Feature: To be able to do something In order to do something As someone I want the system to do this thing Scenario: A sample one Given this situation When I do something Then what I get is what I was expecting for 

毫无疑问,如果testing通过,你可以断言你正在提供一个工作特性。 这就是你可以称之为商业价值

如果你想为DoSomething编写一个unit testing,你应该假装(使用一些模拟)其余的类和方法正在工作(也就是说,这个方法正在使用的所有依赖关系正常工作),并断言你的方法是加工。

在实践中,你做类似的事情

 public SomeResults DoSomething(someInput) { var someResult = [Do your job with someInput]; FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log return someResults; } 

你可以使用dependency injection,或者一些工厂方法或者任何模拟框架,或者只是扩展被testing的类。

假设Log.DoSomething()中存在一个错误。 幸运的是,小黄瓜的规格会发现它,你的端到端testing将会失败。

该function将无法正常工作,因为日志已损坏,而不是因为[用someInput执行您的工作]不是在做它的工作。 顺便说一句,[用一些input来做你的工作]是这个方法的唯一责任。

另外,假设Log用于100个其他特征,100个其他类别的100个其他特征。

是的,100个function将失败。 但是,幸运的是,100个端到端testing也失败了,揭示了这个问题。 而且,是的, 他们说的是实话

这是一个非常有用的信息:我知道我有一个破产的产品。 这也是一个令人困惑的信息:它没有告诉我什么问题在哪里。 它告诉我症状,而不是根本原因。

然而,DoSomething的unit testing是绿色的,因为它使用了一个伪造的Log,永远不会中断。 而且,是的, 这显然是在说谎 。 这是沟通一个破碎的function正在工作。 它如何有用?

(如果DoSomething()的unit testing失败,请确保:[您在someInput上的工作]是否有一些错误。)

假设这是一个破坏类的系统 一个破碎的类的系统

一个bug会破坏几个function,几个集成testing将会失败

一个bug会破坏几个功能,几个集成测试将会失败

另一方面,同样的错误只会打破一个unit testing

同样的错误只会打破一个单元测试

现在,比较两种情况。

同样的错误只会打破一个unit testing

  • 您使用损坏的日志的所有function都是红色的
  • 所有的unit testing都是绿色的,只有Log的unit testing是红色的

实际上,所有使用中断function的模块的unit testing都是绿色的,因为通过使用mock,它们可以去除依赖关系。 换句话说,他们运行在一个理想的,完全虚构的世界。 这是隔离错误并寻找它们的唯一方法。 unit testing意味着嘲笑。 如果你不嘲笑,你不是unit testing。

区别

集成testing告诉什么是不工作的。 但是在猜测问题出在哪里却是没用的。

unit testing是唯一的testing,告诉你究竟在哪里的错误。 为了绘制这些信息,他们必须在模拟环境中运行该方法,其中所有其他依赖关系都应该正常工作。

这就是为什么我认为你的句子“或者仅仅是一个跨越两个class级的unit testing”是不知何故被置换的。 unit testing不应该跨2个类。

这个回答基本上是我写的东西的总结: unit testing的谎言,这就是为什么我爱他们 。

当我编写unit testing时,我将testing代码的范围限制在我正在通过嘲笑依赖关系来编写的类中。 如果我正在写一个Sentence类,而Sentence对Word有依赖,我会用一个模拟的Word。 通过嘲弄Word,我只能关注其界面,并testing我的Sentence类与Word界面交互的各种行为。 这样我只testing句​​子的行为和实现,而不是同时testingWord的实现。

一旦我编写了unit testing,以确保Sentence基于Word界面与Word进行交互时正确运行,我编写了集成testing,以确保我对交互的假设是正确的。 为此,我提供实际的对象,并编写一个testing,练习一个将最终使用句子和单词的function。

我的10位:D

我总是被告知, unit testing是对单个组件的testing – 应该充分运用。 现在,这往往有很多层次,因为大多数组件是由较小的部分组成。 对我而言,一个单位是系统的一个function部分。 所以它必须提供一些有价值的东西(即不是一个stringparsing的方法,而是一个HtmlSanitizer )。

集成testing是下一步,它采取一个或多个组件,并确保他们一起工作,因为他们应该..然后上面的复杂担心如何组件单独工作,但是当你inputHTML到你的HtmlEditControl ,它不知何故神奇地知道它的有效或不。

它是一个真正的可移动的线虽然..我宁愿更多的是让该死的代码工作完全停止^ _ ^

unit testing使用模拟

你所说的是集成testing,它实际上testing你的系统的整体集成。 但是当你做unit testing的时候,你应该分别testing每个单元。 其他一切应该被嘲笑。 所以在你的Sentence类的情况下,如果它使用Word类,那么你的Word类应该被嘲笑。 这样,你只会testing你的Sentence类的function。

我认为当你开始考虑集成testing的时候,你所说的更多的是物理层而不是逻辑层之间的交叉。

例如,如果你的testing关心自己生成的内容,那么这是一个unit testing:如果你的testing只考虑写入磁盘,它仍然是一个unit testing,但是一旦你testing了I / O和文件的内容,那么你有自己的整合testing。 当你在一个服务中testing一个函数的输出时,它是一个unit testing,但是一旦你调用一个服务并且看看函数结果是否相同,那么这就是一个集成testing。

从技术上讲,无论如何你都不能unit testing。 如果你的课程是由其他几个课程组成的呢? 这是否自动使它成为一个整合testing? 我不这么认为。

unit testing:对一个单元或一个最小的软件进行的testing。 完成validation它是否满足其function规格或其预期的devise结构。

集成testing:testing相关模块的组合function。

采用单一责任devise,黑白相间。 它有一个以上的责任,它是一个整合testing。

通过鸭子testing(看,嘎嘎,蹒跚,它是一只鸭子),它只是一个unit testing,在其中有一个以上的新物体。

当你进入mvc并testing它时,控制器testing总是一体化的,因为控制器包含一个模型单元和一个视图单元。 在这个模型中testing逻辑,我会调用一个unit testing。

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

是因为unit testing是你所做的事情,集成testing是你不能做的? 或相反亦然? 当然不是,你应该尽量做到这一点。

是因为unit testing需要快速,独立,可重复,自我validation和及时的集成testing不应该? 当然不是,所有的testing都应该是这些。

这是因为你在unit testing中使用mock,但是你没有在集成testing中使用它们? 当然不是。 这意味着如果我有一个有用的集成testing,我不允许为某个部分添加一个模拟,恐怕我不得不将我的testing重命名为“unit testing”或交给另一个程序员去处理。

是因为unit testingtesting一个单元,集成testingtesting多个单元? 当然不是。 那实际重要的是什么? 关于testing范围的理论讨论无论如何都在实践中被破坏,因为“单位”这个术语完全依赖于上下文。 在课堂上,一个单位可能是一个方法。 在汇编层面上,一个单元可能是一个类,而在服务层面上,一个单元可能是一个组件。 甚至class级也使用其他class级,那么哪个class级呢?

这并不重要。

testing是重要的,第一是重要的,分裂定义的头发是浪费时间,只是混淆新人testing。

用以下术语来思考你的testing的性质:

  • 降低风险 :这是testing的目的。 只有unit testing和集成testing的结合才能使您完全降低风险,因为unit testing本质上不能testing模块之间的适当交互,集成testing只能在很小的程度上执行非平凡模块的function。
  • testing编写工作 :集成testing可以节省工作,因为您不需要编写存根/假货/嘲笑。 但是unit testing也可以节省工作量,当实现那些存根/假货/嘲笑比在没有它们的情况下configurationtesting设置容易。
  • testing执行延迟 :涉及重量级操作的集成testing(例如访问DB或远程服务器等外部系统)往往比较慢。 这意味着unit testing可以更频繁地执行,如果有任何失败,这将减lessdebugging的工作量,因为您可以更好地了解在此期间发生的变化。 如果您使用testing驱动开发(TDD),这变得特别重要。
  • debugging工作 :如果集成testing失败,但没有一个unit testing,这可能是非常不方便的,因为涉及太多的代码可能包含这个问题。 如果您以前只更改了几行,这不是一个大问题 – 但是,由于集成testing运行缓慢,您可能没有在如此短的时间间隔内运行它们。

请记住,集成testing可能仍然存在/伪造/嘲笑它的一些依赖关系。 这为unit testing和系统testing(最全面的集成testing,testing所有系统)提供了大量的中间地带。

所以一个实用的方法是:灵活地依靠集成testing,尽可能多地使用unit testing,而这样做太冒险或不方便。 这种思维方式可能比一些unit testing和集成testing的教条式歧视更有用。

我想我仍然可以调用一些交互类的unit testing,前提是unit testingclass1是testingclass1的特性,而class2的unit testing正在testing它的特性,而且他们没有碰到数据库。

当我通过大部分堆栈运行时,我会调用一个testing集成testing,甚至碰到数据库。

我真的很喜欢这个问题,因为TDD的讨论有时候对我来说太过于纯粹,对我来说,看到一些具体的例子是很好的。

我也这么做 – 我把它们全称为unit testing,但是在某个时候,我有一个覆盖如此之多的“unit testing”,我经常将它重命名为“..IntegrationTest” – 只是名称更改,没有其他更改。

我认为从“primefacestesting”(testing一个微小的类或方法)到unit testing(类级别)和集成testing – 还有functiontesting(通常从上到下覆盖更多的东西)还有一个延续, – 似乎没有一个干净的切断。

如果你的testing设置了数据,并且可能加载了一个数据库/文件等等,那么也许它更像是一个集成testing(我发现使用更less的模拟和更多真实类的集成testing,但是这并不意味着你不能模拟出一些的系统)。

unit testing是一种testing方法,validation源代码的各个单元是否正常工作。

集成testing是软件testing的阶段,其中将各个软件模块作为一个组合进行testing。

Wikipedia将单元定义为应用程序中最小的可testing部分,在Java / C#中是一种方法。 但是在你的Word和Sentence类的例子中,我可能只是写句子的testing,因为我可能会发现使用模拟词类来testing句子类是矫枉过正的。 所以句子是我的单位,单词是单位的实施细节。

如果你喜欢,unit testing是针对一个工作单元或一个代码块进行testing的。 通常由单个开发人员执行。

集成testing是指当开发人员将其代码提交到源代码控制库时,最好在集成服务器上执行的testing。 集成testing可能由Cruise Control等实用程序执行。

所以你做unit testing来validation你所build立的工作单元正在工作,然后集成testingvalidation你添加到存储库的任何东西都不会破坏别的东西。

这个问题有点学术,不是吗? ;-)我的观点:对于我来说,整合testing是对整个部分的testing,而不是如果十个中的两个部分在一起。 我们的集成testing表明,如果主构build(包含40个项目)将成功。 对于这些项目,我们有大量的unit testing。 对于我来说unit testing最重要的是,一个unit testing不能依赖于另一个unit testing。 所以对于我来说,上面描述的testing都是unit testing,如果它们是独立的。 对于集成testing,这不需要太重要。

我把unit testing称为白盒testing类。 类需要的任何依赖被replace为假(嘲笑)。

集成testing是那些同时testing多个类及其交互的testing。 在这些情况下,只有一些依赖是伪造/嘲弄的。

我不会调用Controller的集成testing,除非它们的一个依赖是真实的(即不是伪造的)(例如IFormsAuthentication)。

分离两种types的testing对于在不同级别testing系统是有用的。 此外,集成testing往往是长期存在的,unit testing应该是快速的。 执行速度的区别意味着它们的执行方式不同。 在我们的开发过程中,unit testing是在办理登机手续(这很好,因为他们超级快),集成testing每天运行一次/两次。 我尝试尽可能频繁地运行集成testing,但是通常会触及数据库/写入文件/使得rpc的/ etc速度变慢。

这提出了另一个重要的一点,unit testing应该避免碰到IO(例如磁盘,networking,数据库)。 否则,他们会放慢速度。 devise这些IO依赖需要一点努力 – 我不能承认我一直忠于“unit testing必须快”的规则,但是如果你是这样的话,在一个更大的系统上的好处将变得非常快。

集成testing:testing数据库持久性。
unit testing:数据库访问被模拟。 代码方法经过testing。

有这些testing基本上成为集成testing,因为他们现在testing这两个类的整合? 还是仅仅是一个跨越两个class级的unit testing呢?

我想是和是。 跨越2个class级的unit testing成为一个综合testing。

你可以通过用模拟实现来testingSentence类–MockWord类,这在系统的那些部分足够大以便由不同的开发者实现时是重要的。 在这种情况下,单词是unit testing,句子unit testing与MockWord的帮助,然后句与Word集成testing。

实际区别的实例可以是:1)包含1,000,000个元素的数组很容易进行unit testing,工作正常。 2)BubbleSort很容易在10个元素的模拟数组上进行unit testing,并且工作正常3)集成testing表明某些事情不是很好。

如果这些部分是由单个人开发的,那么在unit testingBubbleSoft时就会发现很可能的问题,因为开发人员已经有了真正的数组,并且他不需要模拟实现。

此外,重要的是要记住,unit testing和集成testing都可以使用例如JUnit自动化和编写。 在JUnit集成testing中,可以使用org.junit.Assume类来testing环境元素(例如数据库连接)的可用性或其他条件。

上面的例子很好,我不需要重复。 所以我会专注于使用示例来帮助您理解。

集成testing

集成testing检查一切是否一起工作。 想象一下在手表中一系列的齿轮一起工作。 整合testing将是:手表是否在正确的时间? 它还在3天内讲出正确的时间吗?

它告诉你的是整体是否工作。 如果失败了:它不会告诉你到底在哪里失败。

unit testing

这些确实是特定types的testing。 他们告诉你一个具体的事情是工作还是失败。 这种types的testing的关键是,它只testing一个特定的东西,而假设其他一切正常工作。 这是关键。

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

  • 我们以汽车为例。
  • 汽车集成testing:例如,汽车开到Echuca后面。 如果是这样的话,你可以放心地说,一辆汽车从整体angular度来看是工作的。 这是一个综合testing。 如果失败,你不知道它实际上失败的地方:是散热器,变速箱,发动机还是化油器? 你不知道。 这可能是任何事情。
  • 汽车的unit testing :发动机正在工作。 这个testing假定汽车里的其他东西都能正常工作。 这样,如果这个特定的unit testing失败了:你可以非常确定问题在于引擎 – 所以你可以快速隔离和修复问题。

混合你的集成和unit testing的后果:

  • 假设你的汽车整合testing失败。 它没有成功地驾驶Echuca。 哪里有问题?

  • 你看你的发动机testing。 但在这种特殊情况下,发动机testing使用外部依赖性:使用特殊的燃料系统。 让我们假设引擎unit testing也失败了。 问题在哪里? (给自己10秒钟才能得到答案。)•发动机是否发生故障,或是发动机失效的燃料系统?

你看到这里的问题? 你不知道什么是失败。 如果你使用10个依赖项,那么每个10个依赖项都可能导致这个问题 – 而且你不知道从哪里开始。 这就是为什么unit testing嘲笑,以为其他一切都工作得很好。

我希望这有帮助。