为什么使用 JUnit 进行测试?

2022-08-31 08:22:28

也许我的问题是新手的问题,但我无法真正理解我在什么情况下会使用

无论我编写简单的应用程序还是更大的应用程序,我都会用语句测试它们,这对我来说很容易接缝。System.out

如果我们仍然必须调用相同的方法,检查它们返回的内容,然后我们有注释所有内容的开销,那么为什么要使用JUnit创建测试类,这是项目中不必要的文件夹?

为什么不编写一个类并立即对其进行测试,而不是创建测试类呢?System.out

PS.我从来没有做过我只是在学习的大型项目上工作过。

那么目的是什么呢?


答案 1

这不是测试,而是“手动查看输出”(在业务中称为LMAO)。更正式地说,它被称为“手动查找异常输出”(LMFAO)。(请参阅下面的注释)

每次更改代码时,都必须对受这些更改影响的所有代码运行应用和 LMFAO。即使在小型项目中,这也是有问题的,并且容易出错。

现在,只要您进行代码更改,即可扩展到 50k、250k、1m LOC 或更多以及 LMFAO。这不仅令人不快,而且是不可能的:你已经扩展了输入,输出,标志,条件的组合,并且很难练习所有可能的分支。

更糟糕的是,LMFAO可能意味着访问一页又一页的Web应用程序,运行报告,在数十个文件和机器上仔细研究数百万条日志行,读取生成和发送的电子邮件,检查短信,检查机器人的路径,填充一瓶苏打水,聚合来自一百个Web服务的数据,检查金融交易的审计线索......你明白了。“输出”不表示几行文本,“输出”表示聚合系统行为。

最后,单元和行为测试定义了系统行为。测试可以由持续集成服务器运行并检查其正确性。当然,也可以,但是CI服务器不会知道其中一个是错误的 - 如果是这样,它们是单元测试,你也可以使用一个框架。System.out

无论我们认为自己有多好,人类都不是好的单元测试框架或CI服务器。


注意:LMAO正在测试,但意义非常有限。它在整个项目中或作为流程的一部分都无法以任何有意义的方式重复。这类似于在REPL中逐步开发,但永远不会将这些增量测试形式化。


答案 2

我们编写测试来验证程序行为的正确性。

通过用眼睛检查输出语句的内容来验证程序行为的正确性是一个手动操作,或者更具体地说,是一个视觉过程。

你可以争辩说

目视检查有效,我检查代码是否做了它应该做的事情,对于这些场景,一旦我可以看到它是正确的,我们就可以开始了。

首先,很高兴您对代码是否正常工作感兴趣。这是一件好事。您走在曲线的前面!可悲的是,这种方法存在问题。

目视检查的第一个问题是,您是一个严重的焊接事故,无法再次检查代码的正确性。

第二个问题是,使用的一双眼睛与眼睛主人的大脑紧密耦合。如果代码的作者也拥有视觉检查过程中使用的眼睛,那么验证正确性的过程依赖于视觉检查员大脑中内化的有关程序的知识。

一双新的眼睛很难进来验证代码的正确性,因为它们没有与原始编码员的大脑合作。第二双眼睛的所有者必须与代码的原始作者交谈,以便完全理解所讨论的代码。众所周知,对话作为分享知识的手段是不可靠的。如果原始编码器对新的眼睛不可用,那么这一点是没有意义的。在这种情况下,新的眼睛必须阅读原始代码。

阅读单元测试未涵盖的其他人的代码比读取具有关联单元测试的代码更困难。在最好的情况下,阅读其他人的代码是棘手的工作,在最坏的情况下,这是软件工程中最繁琐的任务。雇主在宣传职位空缺时,强调一个项目是绿地(或全新的)项目,这是有原因的。从头开始编写代码比修改现有代码更容易,从而使广告工作对潜在员工更具吸引力。

通过单元测试,我们将代码划分为其组成部分。然后,对于每个组件,我们设置了我们的停顿,说明程序应该如何运行。每个单元测试都讲述了程序的该部分在特定场景中应如何操作的故事。每个单元测试都像合约中的一个子句,从客户端代码的角度描述应该发生什么。

这意味着一双新的眼睛在有问题的代码上有实时和准确的文档。

首先,他们有代码本身,实现,代码是如何完成的;其次,他们拥有原始编码人员在一组正式语句中描述的所有知识,这些语句讲述了该代码应该如何表现的故事。

单元测试捕获并正式描述原作者在实现该类时所拥有的知识。它们提供了该类在客户端使用时的行为方式的说明。

您质疑这样做的有用性是正确的,因为可以编写无用的单元测试,不涵盖所有有问题的代码,变得陈旧或过时等等。我们如何确保单元测试不仅模仿而且改进了知识渊博,尽职尽责的作者在运行时直观地检查其代码输出语句的过程?首先编写单元测试,然后编写代码以使该测试通过。当你完成后,让计算机运行测试,它们速度很快,它们擅长执行重复性任务,非常适合这项工作。

通过在每次启动它们测试的代码并为每个生成运行测试时查看它们来确保测试质量。如果测试失败,请立即修复它。

我们自动执行运行测试的过程,以便在每次构建项目时运行测试。我们还自动生成代码覆盖率报告,详细说明测试覆盖和执行的代码百分比。我们力求高百分比。如果某些公司没有编写足够的单元测试来描述代码行为的任何更改,则会阻止将代码更改签入到源代码控制中。通常,第二双眼睛将与更改的作者一起查看代码更改。审阅者将仔细检查更改,以确保更改易于理解并被测试充分覆盖。因此,审查过程是手动的,但是当测试(单元和集成测试以及可能的用户验收测试)通过此手动审查过程时,就会成为自动构建过程的一部分。每次签入更改时都会运行这些操作。服务器在生成过程中执行此任务。

自动运行的测试,维护代码行为的完整性,并帮助防止将来对代码库的更改破坏代码

最后,通过提供测试,您可以积极地重构代码,因为您可以安全地进行重大的代码改进,因为您知道您的更改不会破坏现有测试。

测试驱动开发有一个警告,那就是你必须编写代码,使其具有可测试性。这涉及对接口进行编码,并使用依赖关系注入等技术来实例化协作对象。看看肯特·贝克(Kent Beck)的作品,他很好地描述了TDD。查找接口编码并研究


推荐