我们从哪里开始使用单元测试?

时间:2009-05-13 07:33:34

标签: java java-ee junit

我们从哪里开始使用单元测试?
我对从哪里开始使用单元测试有所怀疑 我正在RAD中使用Junit进行单元测试。在所有代码准备好部署之后,或者在部署之后,我正在执行此操作。我很困惑为什么在代码几乎准备好部署之后我们正在进行单元测试 我的问题是我们应该何时开始进行单元测试?

我还有一些问题......
我在单元测试中所做的是从类中获取一个方法并为该方法创建一个测试类 在该类中,我给该方法提供了一些输入值,并期望数据库中有相应的输出值 现在,单个测试类确实采用输入值 - >将其传递给方法 - >从原始类调用方法 - >数据库连接 - >从DB->获取值;将其返回到测试类。

如果测试成功运行,那么Junit控制台会显示Green Bar else Red bar 红色条带有错误原因。但它不会生成任何单元测试报告。

现在这是我的问题......
我正在进行正确的单元测试吗?由于单个单元测试方法包含所有代码流并给出结果......

7 个答案:

答案 0 :(得分:4)

现在开始进行单元测试的最佳时间(如果还没有)。单元测试最有效的用途是测试驱动开发(TDD),在其中您在实现它时为每个方法编写测试(编写失败的测试,然后实现方法以使其通过)。但是,以后添加测试还为时不晚。 JUnit测试巩固了有关可能在以后更改的代码的某些假设。如果假设发生变化,那么测试就会中断,你可能会从一些很难发现的错误中解脱出来。

我不知道报告工具,但你可以添加一个JUnit ANT任务,它将测试结果输出到你的构建控制台(如果捕获了ant输出,则输出日志)。

您的数据库测试听起来像小集成测试而不是单元测试。这很好,但是如果测试太慢,你可能会考虑使用模拟对象(通过像JMock或EasyMock这样的框架)来替换真实的数据库连接。这将方法的逻辑与数据库的状态和行为隔离开来,让您可以运行测试而无需担心数据库是否正在运行并存储测试数据。

有用的链接:

http://en.wikipedia.org/wiki/Test-driven_development

http://www.jmock.org/

http://easymock.org/

http://ideoplex.com/id/25/ant-and-junit

http://ant.apache.org/manual/Tasks/junit.html

http://misko.hevery.com/code-reviewers-guide/(编写可单元测试代码的指南)

[编辑 - 回复评论]: 关于你所做的是否是正确的单元测试,技术上答案是“不”。正如我所说的,它更像是一个集成测试,这很好,但它做得太多,并且有太多的依赖性被认为是一个真正的单元测试。理想情况下,单元测试将测试方法中的逻辑而不是依赖项。编写上面提到的可测试代码的指南(以及Misko Hevery的相关博客)提供了一些很好的建议,关于如何编写带有接缝的代码来插入依赖的模拟。 Michael Feathers在他出色的着作Working Effectively with Legacy Code中深入探讨了这一主题。

关键因素是依赖注入:可测试方法不查找它们的依赖关系 - 它们在构造函数中接收它们或作为参数。如果这需要过多的重构,那么您可以尝试一些技巧,例如将寻找依赖关系的代码移动到您可以覆盖的受保护或包可见方法中。那么你在一个子类上运行测试,该子类从这些方法返回模拟对象。

答案 1 :(得分:3)

您应该尽可能早地编写测试,最好是在编写实现之前。

这是一本我发现在这个主题上有用的书,可能值得一读...... http://www.amazon.com/Test-Driven-Development-Addison-Wesley-Signature/dp/0321146530

为了尝试解决您的第二点,您所描述的是“集成测试”,即它不仅测试您的代码单元,还测试您的数据库连接,配置,数据等。

单元测试应该只测试您关注的代码的特定“部分”。即调用您的方法应该只测试该方法。它不应该关注数据库连通性和数据访问。您可以使用“Mock”对象来实现此操作,以充当依赖项的临时替代。

请参阅:http://msdn.microsoft.com/en-us/library/aa730844.aspx

虽然本文档来自Microsoft并且您使用的是java,但同样的原则也适用。

希望这有帮助。

答案 2 :(得分:2)

您应该尽早开发单元测试。实际上,最好的解决方案是在实现要测试的类之前开发它们。然后在每次向类中添加重要功能时运行它们。

单位测试,顾名思义,用于测试“单位”操作。你不应该只有一个测试表现太多。单元测试也应该是测试单个类的功能。

您在此处描述的内容似乎更像是系统测试。这是件好事,但它与单元测试完全不同。

答案 3 :(得分:0)

进行认证开发需要您遵循已定义的开发模型。最常用的模型是V模型,简单地说,它定义了要求,规格,子规格(例如组件,模块或单位的规格)等。自上而下到V的左侧分支。最后到达底部的V当规格定义一个不能合理地分解成较小部分的原子单元时。

在V模型的右侧分支上,执行验证,以便开发的模块符合其规格和/或要求。通常在并行或在实现UUT(被测单元)之前创建测试。 通过这种方式,您可以确保任何模块从开始就适合其框架,甚至在进行一些返工时也是如此。

正如其他人所说,尽可能使用模拟等尽可能简化测试。您还应该自动化测试,至少那些与位于V底部附近的模块有关的测试,因为这些测试通常比顶部附近的测试运行得多。

当您的测试具有明确定义的输出时,执行正确的报告会更容易。我们通常有枚举的结构(传递,失败,错误)状态编号和消息文本。

答案 4 :(得分:0)

在我看来,测试应该从你完成第一种方法的那一刻开始。

在编写方法时测试方法有很多帮助。首先,当出现问题并且你唯一的线索是它在特定的类中时,如果该类有无数的方法和属性,那么很难弄清楚出了什么问题。显然,如果您遇到语法错误,那么当您将一百万种方法投入到争论中时,语义错误会变得非常棘手。

确保每个单独的方法都起作用,这是最精细的保证级别,它说明了整个类的稳定性。如果您对特定方法应该做什么有具体的定义,单元测试不仅可以防止边缘情况语义错误,还可以帮助您预先规划程序流,这可以帮助您避免大规模重构,或者更糟,重写。

为了进行有效的测试,请确保您将课程分解为尽可能多的方法。我知道有些人可能不同意这一点,但是在远离函数其余部分的上下文中执行操作的逻辑的重要部分应该被移动到它们自己的函数中,以便可以独立地进行测试。我不会在您的单元测试中执行SQL查询。相反,使用模拟对象来模仿数据库。测试数据库不是单元测试。

这不仅可以帮助您确保应用程序的完整性,而且还可以在将来需要重构部分类时帮助您。在100线函数中搜索三行逻辑是没有意义的。如果这些逻辑部分采用自己的方法,那么您可以放心,由于该逻辑,您的方法不会失败。如果某个函数的怪物失败了,那么关于函数的哪个部分实际导致错误的线索就会更少。

我知道这一切可能听起来多余,但我的观点是提前测试,测试通常不仅有助于程序的稳定性,还可以帮助您编写干净的代码,避免遇到小错误的麻烦。

答案 5 :(得分:0)

  

我的问题是什么时候应该   开始单元测试?

不是“在所有代码准备好部署之后”。不是“部署后”。那太晚了。正如许多其他人所建议的那样,最好的时间是(只是)在编写代码之前,TDD风格。

  

现在这是我的问题......我在做什么   正确的单元测试?既然单身   单元测试方法包括所有代码   流动并给出结果......

您没有进行“正确”的单元测试。您正在测试的单元是类方法,但它也在测试数据库连接,这通常会使测试运行速度太慢而不能像我们想的那样频繁运行,而且很脆弱。这并不是说你的测试没用 - 它们可能很有用 - 它们只是不好的单元测试。

假设您的数据库中包含正确的数据,并且您的程序与其有完整的连接。您的方法在测试过程中从数据库中获得了什么价值?只需将该值直接放入,即可测试此方法的功能。所以即使没有数据库也能运行。那是什么?你的方法不行吗?也许它做得太多了。也许它是(a)从数据库获取数据和(b)进行计算。也许你真的想测试(b)(我认为你这样做)。因此,将(a)和(b)分开,给自己一个接缝(根据Michael Feathers的术语),您可以从测试方法中注入测试数据。你现在有什么?更好的设计。每个方法只做一个事情。松耦合。你到了那里因为你的测试带领你到那里。 是测试驱动的开发。

答案 6 :(得分:0)

每当您进行更改或编写新代码时,都应该包含对每个输入组合的测试。编写代码永远不会结束,有人,某些时候必须返回并进行修复或增强,而您的测试将帮助他们知道他们所做的更改没有破坏任何内容。