如何在遗留项目中实现测试框架

时间:2009-11-30 15:30:58

标签: php javascript frameworks testing

我有一个用PHP和Javascript编写的大项目。问题是它变得如此庞大且不可维护,改变代码的一小部分会令人不安,并可能会破坏很多其他部分。

我真的很难测试我自己的代码(事实上,其他人每天指出这一点),这使得维护项目变得更加困难。

项目本身并不复杂或复杂,它的构建方式更加复杂:我们在进行测试时没有预定义的规则或列表。这通常会导致许多错误和不满意的客户。

我们开始在办公室讨论这个问题,并提出了开始使用测试驱动开发而不是像地狱一样开发的想法,也许稍后会进行测试(这几乎总是最终修复错误)。

在那个背景之后,我需要帮助的事情如下:

  1. 如何实施测试 框架已经存在 项目? (3年) 制作和计数)

  2. 有什么样的框架 用于检测?我想我需要一个 Javascript和。的框架 一个用于PHP。

  3. 什么是测试的最佳方法 图形用户界面?

  4. 我之前从未使用过单元测试,所以这对我来说真是个未知领域。

11 个答案:

答案 0 :(得分:6)

天儿真好,

修改:我刚看了一下“The Art of Unit Testing”的第一章,a free PDF也提供了book's website。它将为您提供有关单元测试尝试的内容的概述。

我假设您将使用xUnit类型框架。一些最初的高层次想法是:

  1. 修改:确保每个人都同意什么是良好的单元测试。我建议使用上面的概述章作为一个很好的起点,如果需要,可以从那里开始。想象一下,让人们热情地跑去创造大量的单元测试,同时对“好”的单元测试有不同的理解。将来25%的单元测试无用,可重复,可靠等等,这对你来说太可怕了。
  2. 添加测试以一次覆盖小块代码。也就是说,不要创建单个整体任务来为现有代码库添加测试。
  3. 修改任何现有进程,以确保为编写的任何新代码添加新测试。使其成为代码审查过程的一部分,必须为新功能提供单元测试。
  4. 扩展任何现有的错误修正过程,以确保创建新的测试以显示存在并证明没有错误。注:不要忘记回滚您的候选修复程序再次引入该错误,以验证只有那个纠正问题的单个补丁并且它没有被多种因素修复。
  5. 编辑:当您开始构建测试数量时,开始将它们作为夜间回归测试运行,以检查新功能是否已损坏任何内容。
  6. 为候选错误修正程序的审核流程成功运行所有现有测试和录入标准。
  7. 编辑:开始保留测试类型的目录,即测试代码片段,以便更轻松地创建新测试。没有任何意义重新发明轮子。为测试在代码库的一部分中打开文件而编写的单元测试将类似于写入测试代码的单元测试,该测试代码在代码库的不同部分打开不同的文件。 将这些目录编目以便于查找。
  8. 编辑:您只修改现有类的几个方法,创建一个测试套件来保存该类的完整测试集。然后,仅将要修改的方法的各个测试添加到此测试套件中。这使用xUnit termonology,因为我现在假设您将使用像PHPUnit这样的xUnit框架。
  9. 使用标准惯例来命名测试套件和测试,例如: testSuite_classA然后将包含各个测试,如test__test_function。例如,test_fopen_bad_name和test_fopen_bad_perms等。这有助于最小化在代码库中移动并查看其他人的测试时的噪音。它还有助于帮助人们在他们首先命名他们的测试时,通过释放他们的思想来处理更有趣的事情,如测试本身。
  10. 编辑:我不会在此阶段使用TDD。根据定义,TDD将需要在更改到位之前进行所有测试,因此当您添加新的testSuite以覆盖您正在处理的类时,您将在整个地方进行失败的测试。而是添加新的testSuite,然后根据需要添加单个测试,这样您的测试结果中就不会出现大量噪声,导致测试失败。而且,正如Yishai指出的那样,在这个时间点添加学习TDD的任务将会让你失望。将学习TDD作为您有空余时间的任务。这并不困难。
  11. 作为推论,你需要一个工具来跟踪testSuite存在的那些现有类,但是还没有编写测试来覆盖类中的其他成员函数。通过这种方式,您可以跟踪测试覆盖范围的漏洞。我在这里谈论的是一个高级别,你可以生成一个类列表和特定的成员函数,当前不存在任何测试。测试和testSuite的标准命名约定将极大地帮助您。
  12. 我会在想到它们时添加更多积分。

    HTH

答案 1 :(得分:6)

你应该给自己一份副本Working Effectively with Legacy Code。这将为您提供有关如何将测试引入未编写的代码的良好指导。

TDD很棒,但您需要首先将现有代码置于测试之下,以确保您所做的更改在引入更改时不会更改现有的必需行为。

然而,现在引入TDD会让你在退回之前减慢很多,因为改造测试,即使只是在你正在改变的区域,在变得简单之前会变得复杂。

答案 2 :(得分:5)

只是为了增加其他优秀的答案,我同意一次性从0%到100%的覆盖率是不现实的 - 但是你应该每次修复bug时都应该添加单元测试

你说有很多错误和不满意的客户 - 我非常积极地将严格的TDD纳入错误修正过程,这比整体实施它要容易得多。毕竟,如果确实存在需要修复的错误,那么创建一个再现它的测试可以实现各种目标:

  • 这可能是一个最小的测试用例来证明确实存在问题
  • 有信心(当前失败的)测试突出显示报告的问题,您将确定您的更改是否已修复它
  • 它将永远作为一种回归测试,可以防止将来再次出现同样的问题。

将测试引入现有项目很困难并且可能是一个漫长的过程,但在修复错误的同时进行测试是一个理想的时间(与在“正常”意义上逐渐引入测试同时进行)如果不抓住机会并从你的错误报告中制作柠檬水,那将是一种耻辱。 : - )

答案 3 :(得分:3)

从规划的角度来看,我认为你有三个基本选择:

  1. 采用循环来使用单元测试来改进代码
  2. 指定团队的一部分,使用单元测试来改进代码
  3. 在处理代码时逐步引入单元测试
  4. 第一种方法可能比你预期的要持续更长时间,并且你的可见生产力将受到打击。如果您使用它,您将需要获得所有利益相关者的支持。但是,您可以使用它来启动该过程。

    第二种方法的问题在于您在编码器和测试编写器之间进行区分。编码人员不会对测试维护感到任何所有权。我认为这种方法值得避免。

    第三种方法是最有机的,它可以让你从一开始就进入测试驱动的开发。积累有用的单元测试可能需要一些时间。测试积累的缓慢步伐实际上可能是一个优势,因为它让你有时间擅长编写测试。

    考虑到所有因素,我认为我会选择以方法1的精神进行适度的冲刺,然后承诺接近3.

    对于单元测试的一般原则,我推荐Gerard Meszaros的书xUnit Test Patterns: Refactoring Test Code

答案 4 :(得分:2)

我使用PHPUnit效果很好。与其他JUnit派生项目一样,PHPUnit要求将要测试的代码组织到类中。如果你的项目不是面向对象的,那么你需要开始将非过程代码重构为函数,并将函数重构为类。

我个人并没有使用过JavaScript框架,但我认为这些框架还需要将代码构建成(至少)可调用函数(如果不是完整的对象)。

对于测试GUI应用程序,您可能会因使用Selenium而受益,尽管具有良好QA本能的程序员编写的核对表可能正常工作。我发现使用MediaWiki或您喜欢的Wiki引擎是存储清单和相关项目文档的好地方。

答案 5 :(得分:0)

在大多数情况下,实现框架是一项复杂的任务,因为您开始使用一些新的实体框架部件重新构建旧代码。那些旧部件必须开始与框架通信。旧部件必须接收一些回调和返回状态,旧部件必须以某种方式指出用户,实际上你突然有2个系统要测试。

如果你说你的应用程序本身并不复杂但是由于缺乏测试而导致它可能是重建应用程序的更好选择。将Zend等常用框架放入测试中,收集您的需求,找出测试框架是否符合要求,并确定重新开始是否有用。

我不太确定单元测试,但NetBeans有一个内置的单元测试套件。

答案 6 :(得分:0)

如果代码非常混乱,那么进行任何单元测试都很困难。只有足够松散耦合且设计得足够好的组件才能轻松进行单元测试。但是,在您的情况下,功能测试可能更容易实现。我建议你看看Selenium。使用此框架,您将能够同时测试GUI和后端。但是,最有可能的是,它不会帮助您捕获错误以及单元测试。

答案 7 :(得分:0)

也许此列表可以帮助您和您的伙伴重新构建所有内容:

  1. 使用UML设计和处理异常(http://en.wikipedia.org/wiki/Unified_Modeling_Language
  2. 使用BPMS来设计您的工作流程,这样您就不会挣扎(http://en.wikipedia.org/wiki/Business_process_management
  3. 获取一个也支持javascript后端的php框架列表(例如Zend with jQuery)
  4. 比较这些框架,并选择与您的项目设计和之前使用的编码结构最匹配的框架
  5. 您应该考虑使用ezComponents和Dtrace之类的东西进行调试和测试
  6. 不要害怕改变;)

答案 8 :(得分:0)

对于GUI测试,您可能需要查看Selenium(正如Ignas R已经指出的那样)或者您也可以查看此工具:STIQ

祝你好运!

答案 9 :(得分:0)

在某些情况下,进行自动测试可能不是一个好主意,特别是当代码库很脏并且PHP将其行为与Javascript混合时。

最好先从一个简单的清单(带链接,使其更快)开始,在每次交付之前应该(手动)对事物进行测试。

在3年的雷区进行编码时,通过许多错误检查可以更好地保护自己。为每个案例编写正确的错误消息所花费的15分钟不会丢失。

使用桥接方法:桥接丑陋冗长的函数fold(),调用fnew(),它是一些干净类的包装,调用fold和fnew,比较结果,记录差异,将代码抛入生产中等待为你的鱼。执行此操作时,始终使用一个循环进行重构,另一个循环用于更改结果(甚至不修复旧行为中的错误,只需桥接它)。

答案 10 :(得分:0)

我同意KOHb,Selenium是必须的!

另请查看PHPure

他们的软件记录来自一个有效的php网站的输入和输出,然后自动为不访问外部源(db,文件等)的函数编写phpunit测试。

这不是100%的解决方案,但它是一个很好的开始