单元测试和功能测试有什么区别?

464

单元测试和功能测试有什么区别?单元测试能否也测试函数?


3
参见:https://dev59.com/3kfSa4cB1Zd3GeqPAMod和https://dev59.com/FnE95IYBdhLWcg3wn_Vr。 - user65663
我投票关闭此问题,因为它更像是一个“软件工程”问题,适合在https://softwareengineering.stackexchange.com/上提问。 - nbro
14个回答

574
单元测试告诉开发人员代码的实现是正确的;功能测试告诉开发人员代码是否实现了“正确的”功能。可以将建房子比喻为系统开发,单元测试就像验房师检查房子的内部系统,如基础、框架、电气和水管等,确保它们能够正确且安全地工作,并符合建筑规范;功能测试则类似于房主检查房子,关注的是房屋的外观和使用体验,如房间大小和窗户位置等,以用户的视角对系统进行测试。因此,单元测试是由程序员编写的,功能测试是由用户编写的。详细信息请参阅:单元测试与功能测试

27
对于新接触这个概念的人来说,这句话有些含糊不清。 - user65663
2
@fig-gnuton,我尝试详细说明,希望不会让描述变得模糊。在他们提供的链接中,有一个很好的例子,如果您认为这可能有助于OP,我可以更新答案并引用该语录。 - Anthony Forloney
187
也许另一种表达方式是,“单元测试确保代码按照程序员的意愿运行,功能测试确保程序员按照客户的要求开发代码”? - JS.
4
我喜欢这个,但会进行调整。一个“功能测试”确保应用程序允许用户执行操作。一个“单元测试”确保代码的行为符合程序员的预期。 - Adam
2
程序员想要的不正是与最终用户所需一致吗?为什么编写一个与客户期望不符的测试呢? - O.Badr
显示剩余2条评论

277

单元测试 - 测试一个独立的单元,例如类中的方法(函数),并使用所有依赖项进行模拟。

功能测试 - 也称为集成测试,测试系统中的一个功能片段。这将测试许多方法,并可能与依赖项交互,如数据库或Web服务。


207
让我不同意“AKA Integration Test”。集成测试是检查代码中2个或多个系统/子系统之间的集成。例如,通过ORM检查SQL查询,检查ORM和数据库是否良好配合。从我的看法来说,“Functional Tests”也叫“End to End”。 - graffic
12
我同意@graffic的观点,功能测试并不等同于集成测试。你可能会混淆了系统中子组件之间的“集成”,比如状态持久化等。但总体来说,集成测试的范围要广得多。 - nabster
5
没错,我对任何事情都没有困惑。 - bpapa
4
集成测试是功能测试的一种,但反之则不成立。请搜索“功能与非功能测试”,查看“图片”以获取更多信息。 - Andrejs
10
这个答案完全错误!功能测试和集成测试根本不一样。 - yakya
显示剩余2条评论

153
  • 一个单元测试用来测试一个独立的行为单元。什么是行为单元?它是系统中能够被独立单元测试的最小部分。(这个定义实际上是循环的,也就是说根本不是一个定义,但在实践中似乎相当有效,因为你可以凭直觉有点理解它。)

  • 一个功能测试用来测试一个独立的功能模块。


    • 行为单元非常小:虽然我绝对不喜欢“每个方法一个单元测试”的愚蠢口号,但从大小角度看,它基本上是正确的。行为单元通常是方法的一部分,或者可能是几个方法,最多是一个对象,但不会超过一个对象。

    • 一个功能模块通常包括许多方法,并跨越多个对象和多个架构层次。


    • 例如单元测试:当我调用validate_country_code()函数并传递国家代码'ZZ'时,它应该返回false

    • 例如功能测试:当我在运输表单中填写国家代码为ZZ时,我应该被重定向到一个帮助页面,该页面允许我从菜单中选择我的国家代码。


    • 单元测试是由开发人员编写的,从开发人员的角度出发,为开发人员编写。

    • 功能测试可以面向用户,这种情况下它们是由开发人员与用户(或者在使用正确的工具和合适的用户的情况下,甚至是由用户自己)一起编写的,为用户编写,从用户的角度出发。或者它们可以面向开发人员(例如当它们描述用户不关心的某个内部功能时),这种情况下它们是由开发人员编写的,为开发人员编写,但仍然是从用户的角度出发。

  • 在前一种情况下,功能测试可以作为验收测试,用于将功能需求或功能规范编码为可执行的形式,在后一种情况下,它们也可以用作集成测试。

  • 单元测试经常更改,功能测试应该在主要版本发布期间永远不会更改。


  • 6
    在许多项目中,主版本号的更改用于表示向后不兼容,而如果主版本号更改,则保证向后兼容。什么是“向后兼容性”?它意味着“不改变用户可见的行为”。功能测试是对用户可见的行为规范的可执行编码。因此,如果主版本号不更改,则功能测试也不允许更改;反之,如果功能测试发生更改,则主版本号必须更改。 - Jörg W Mittag
    2
    注意:我并没有提到添加功能测试!是否将之前不存在的功能添加到项目中,这是否构成向后不兼容的更改,取决于该项目。对于最终用户软件,可能不是这样。但是对于编程语言?也许:例如,引入一个新关键字会使当前正在使用该关键字作为变量名的程序无效,因此是向后不兼容的更改。 - Jörg W Mittag
    3
    @JörgWMittag 喜欢这个想法:“功能测试是用户可见行为规范的可执行编码”……无论其他超级专家是否同意,它都对我原来的问题有所帮助,即“它们之间的区别”。 - mike rodent
    @mikerodent:这实际上是在Merb中使用的,我就是从那里得到的灵感。当发布版本时,功能测试被移动到一个子目录中,例如tests/functional/1.0.0,并且不允许更改这些测试。所有未来的点发布,例如1.0.3,都必须通过1.0.0中的所有测试。对于次要发布,例如1.2.0,您只能添加新测试,而不能删除或更改旧测试,您必须通过1.0.0、1.1.0和1.2.0中的所有测试。删除或更改测试需要进行主要发布(2.0.0)。基本上,这将“错误修复”、“向后兼容的添加”...的定义联系起来。 - Jörg W Mittag
    1
    一个功能测试的例子是:当我在运输表格中填写ZZ国家代码时,应该会重定向到一个帮助页面,让我从菜单中选择我的国家代码。这有点挑剔,但我会称之为“验收测试”。功能测试将测试在运输表格中输入ZZ是否将用户转发到正确的URL或抛出特定的异常或错误。 - Bob Ray
    显示剩余6条评论

    116

    简而言之:

    回答这个问题:单元测试是功能测试的一个子类型


    有两个主要的测试组: 功能性非功能性测试。我找到的最好(不是详尽无遗的)说明如下(来源:www.inflectra.com):

    enter image description here

    (1) 单元测试:测试小段代码(函数/方法),也可以被视为(白盒)功能测试。
    当函数组合在一起时,你会创建一个模块=一个独立的部分,可能带有用户界面,可以进行测试(模块测试)。一旦你至少有两个单独的模块,然后将它们粘合在一起,然后就是:
    (2) 集成测试:当您将两个或多个(子)模块或(子)系统放在一起并查看它们是否相互协作时。
    然后集成第三个模块,然后按您或您的团队认为合适的顺序集成第四个和第五个模块,一旦所有拼图块都放置在一起,就会出现
    (3) 系统测试:作为整体测试软件。这基本上是“所有部分的集成测试”。
    如果一切正常,那么接下来就是:
    (4) 验收测试:我们是否实际构建了客户要求的内容?当然,验收测试应该在整个生命周期中进行,而不仅仅是在最后阶段进行,这样您就会意识到客户想要一辆跑车,而您却建造了一辆货车。请注意保留HTML标签。

    enter image description here


    5
    我在谷歌上看到了很多这样的图片,将“单元测试”描述为“功能测试”的一种。但是,这里的其他答案却描述了完全不同的概念: “功能测试”是端到端测试,而“单元测试”则不是功能测试?我感到困惑。是有两种不同的“派别”定义了“功能测试”的术语吗? - Ruslan Stelmachenko
    答案(即使是高赞的)也可能是错误的 ;) - Andrejs
    1
    我喜欢这张图片,但是对于系统集成测试来说,拼图应该看起来“完整”,没有其他拼图可以连接。 - Jonathon Reinhart
    6
    @JonathonReinhart - 不一定。开放边缘可以代表系统容易扩展新功能,这特别有用如果采用敏捷开发等开发方法。 - Myles
    2
    从上面多个相互矛盾的答案中可以看出,“功能测试”显然不是一个标准化的术语,对不同的人有不同的含义。 - Penghe Geng
    显示剩余2条评论

    14
    “功能测试”并不意味着你在测试你代码中的某个函数(方法)。通常情况下,它指的是测试系统的功能性--比如,在命令行中运行foo file.txt,文件file.txt中的文本被翻转了。相比之下,单元测试一般覆盖单个方法的单个用例 -- length("hello") 应该返回5,而length("hi")应该返回2。
    另请参阅IBM对单元测试和功能测试之间界限的看法(英文链接): IBM's take on the line between unit testing and functional testing

    嗯,很有趣,但你展示的链接意味着不同的事情:功能是通过实现来执行的功能,即从用户的角度进行测试,这是用户的功能。 - Stefano Scarpanti

    9
    根据ISTQB的说法,这两者是不可比较的。功能测试与集成测试不同。
    单元测试是测试级别之一,而功能测试则是测试类型。
    基本上:
    系统(或组件)的功能是“它所做的事情”。这通常在需求规格说明书、功能规格说明书或用例中描述。
    然而,
    组件测试,也称为单元、模块和程序测试,旨在查找缺陷,并验证可单独测试的软件(例如模块、程序、对象、类等)的功能。
    根据ISTQB的说法,组件/单元测试可以是功能或非功能的:
    组件测试可能包括对功能以及特定的非功能特性(如资源行为(例如内存泄漏),性能或鲁棒性测试)的测试,以及结构测试(例如决策覆盖率)。
    引用自ISTQB认证的《软件测试基础》。

    我同意关于太多废话的观点,但无论如何他们是最大的玩家,而且这个问题是关于理论的,所以我认为ISTQB应该足够好。 - Dominik

    7
    在Rails中,unit文件夹用于存放模型的测试,functional文件夹用于存放控制器的测试,而integration文件夹用于存放涉及多个控制器交互的测试。Fixture是一种组织测试数据的方式,它们驻留在fixtures文件夹中。test_helper.rb文件保存了测试的默认配置。 您可以访问此链接

    5

    简单来说:

    • 黑盒测试:类似于功能测试的用户界面测试
    • 白盒测试:类似于单元测试的代码测试

    了解更多,请点击这里


    4

    据我所知,单元测试并不等同于功能测试。举个小例子来解释一下。假设你想要测试一个电子邮件Web应用的登录功能是否工作正常,就像一个用户那样。为此,你需要编写以下这种功能测试。

    1- existing email, wrong password -> login page should show error "wrong password"!
    2- non-existing email, any password -> login page should show error "no such email".
    3- existing email, right password -> user should be taken to his inbox page.
    4- no @symbol in email, right password -> login page should say "errors in form, please fix them!" 
    

    我们的功能测试是否应该检查是否可以使用无效输入进行登录?例如,电子邮件没有@符号,用户名有多个点(只允许一个点),.com出现在@之前等。一般来说,不需要!这种测试应该放入单元测试中。

    您可以像下面的测试中所示,在单元测试中检查是否拒绝了无效输入。

    class LoginInputsValidator
      method validate_inputs_values(email, password)
        1-If email is not like string.string@myapp.com, then throw error.
        2-If email contains abusive words, then throw error.
        3-If password is less than 10 chars, throw error.
    

    请注意,功能测试4实际上正在执行单元测试1所做的工作。有时,功能测试可以出于不同的原因重复一些(而不是全部)由单元测试完成的测试。在我们的示例中,我们使用功能测试4检查是否在输入无效输入时出现特定的错误消息。我们不想测试所有不良输入是否被拒绝。那是单元测试的工作。


    1
    关于功能测试通常比单元测试(在功能测试更加专注于基本证明预期的功能是否实现)范围要窄得多这一点说得不错,但我认为它们描述了不同的维度(单元测试中的_composition_与功能测试中的_purpose_); 有些单元测试是功能测试,有些功能测试是单元测试,但也有很多Venn图并没有重叠。 - Myles
    功能测试的范围内和范围外的好例子。 - Myles

    3
    我认为它的意思是:单元测试确保代码执行了你预期的操作(例如,你想要添加参数a和b,实际上你添加了它们,而没有减去它们),功能测试测试所有代码一起工作以获得正确的结果,因此你预期代码在系统中实际上得到了正确的结果。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接