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

时间:2023-01-13 16:33:07

I've got a big project written in PHP and Javascript. The problem is that it's become so big and unmaintainable that changing some little portion of the code will upset and probably break a whole lot of other portions.

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

I'm really bad at testing my own code (as a matter of fact, others point this out daily), which makes it even more difficult to maintain the project.

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

The project itself isn't that complicated or complex, it's more the way it's built that makes it complex: we don't have predefined rules or lists to follow when doing our testing. This often results in lots of bugs and unhappy customers.

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

We started discussing this at the office and came up with the idea of starting to use test driven development instead of the develop like hell and maybe test later (which almost always ends up being fix bugs all the time).

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

After that background, the things I need help with are the following:

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

  1. How to implement a test framework into an already existing project? (3 years in the making and counting)

    如何将测试框架实现到现有项目中? (制作和计算3年)

  2. What kind of frameworks are there for testing? I figure I'll need one framework for Javascript and one for PHP.

    有哪些框架可供测试?我想我需要一个Javascript框架和一个PHP框架。

  3. Whats the best approach for testing the graphical user interface?

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

I've never used Unit Testing before so this is really uncharted territory for me.

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

11 个解决方案

#1


6  

G'day,

天儿真好,

Edit: I've just had a quick look through the first chapter of "The Art of Unit Testing" which is also available as a free PDF at the book's website. It'll give you a good overview of what you are trying to do with a unit test.

编辑:我刚刚浏览了“单元测试艺术”的第一章,该书也可以在本书的网站上以免费PDF格式获得。它将为您提供一个很好的概述,您正在尝试使用单元测试。

I'm assuming you're going to use an xUnit type framework. Some initial high-level thoughts are:

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

  1. Edit: make sure that everyone is is agreement as to what constitutes a good unit test. I'd suggest using the above overview chapter as a good starting point and if needed take it from there. Imagine having people run off enthusiastically to create lots of unit tests while having a different understanding of what a "good" unit test. It'd be terrible for you to out in the future that 25% of your unit tests aren't useful, repeatable, reliable, etc., etc..
  2. 编辑:确保每个人都同意什么是良好的单元测试。我建议使用上面的概述章作为一个很好的起点,如果需要,可以从那里开始。想象一下,让人们热情地跑去创造大量的单元测试,同时对“好”的单元测试有不同的理解。对你来说,25%的单元测试没有用,可重复,可靠等等,这对你来说太可怕了。
  3. add tests to cover small chunks of code at a time. That is, don't create a single, monolithic task to add tests for the existing code base.
  4. 添加测试以一次覆盖小块代码。也就是说,不要创建单个整体任务来为现有代码库添加测试。
  5. modify any existing processes to make sure new tests are added for any new code written. Make it a part of the review process of the code that unit tests must be provided for the new functionality.
  6. 修改任何现有进程以确保为编写的任何新代码添加新测试。使其成为代码审查过程的一部分,必须为新功能提供单元测试。
  7. extend any existing bugfix processes to make sure that new tests are created to show presence and prove the absence of the bug. N.B. Don't forget to rollback your candidate fix to introduce the bug again to verify that it is only that single patch that has corrected the problem and it is not being fixed by a combination of factors.
  8. 扩展任何现有的错误修复过程,以确保创建新的测试以显示存在并证明没有错误。注:不要忘记回滚您的候选修复程序再次引入该错误,以验证它只是纠正问题的单个修补程序,而不是由多种因素组合修复。
  9. Edit: as you start to build up the number of your tests, start running them as nightly regression tests to check nothing has been broken by new functionality.
  10. 编辑:当您开始构建测试数量时,开始将它们作为夜间回归测试运行,以检查新功能是否已破坏任何内容。
  11. make a successful run of all existing tests and entry criterion for the review process of a candidate bugfix.
  12. 为候选bugfix的审查过程成功运行所有现有测试和进入标准。
  13. Edit: start keeping a catalogue of test types, i.e. test code fragments, to make the creation of new tests easier. No sense in reinventing the wheel all the time. The unit test(s) written to test opening a file in one part of the code base is/are going to be similar to the unit test(s) written to test code that opens a different file in a different part of the code base. Catalogue these to make them easy to find.
  14. 编辑:开始保留测试类型的目录,即测试代码片段,以便更轻松地创建新测试。没有任何意义重新发明*。为测试在代码库的一部分中打开文件而编写的单元测试将类似于写入测试代码的单元测试,该测试代码在代码库的不同部分中打开不同的文件。将这些目录编目以便于查找。
  15. Edit: where you are only modifying a couple of methods for an existing class, create a test suite to hold the complete set of tests for the class. Then only add the individual tests for the methods you are modifying to this test suite. This uses xUnit termonology as I'm now assuming you'll be using an xUnit framework like PHPUnit.
  16. 编辑:您只修改现有类的几个方法,创建一个测试套件来保存该类的完整测试集。然后,仅将要修改的方法的各个测试添加到此测试套件中。这使用xUnit termonology,因为我现在假设您将使用像PHPUnit这样的xUnit框架。
  17. use a standard convention for the naming of your test suites and tests, e.g. testSuite_classA which will then contain individual tests like test__test_function. For example, test_fopen_bad_name and test_fopen_bad_perms, etc. This helps minimise the noise when moving around the code base and looking at other people's tests. It also has then benefit of helping people when they come to name their tests in the first place by freeing up their mind to work on the more interesting stuff like the tests themselves.
  18. 使用标准约定来命名测试套件和测试,例如: testSuite_classA然后将包含各个测试,如test__test_function。例如,test_fopen_bad_name和test_fopen_bad_perms等。这有助于最小化在代码库中移动并查看其他人的测试时的噪音。它还有助于帮助人们在他们首先命名他们的测试时,通过释放他们的思想来处理更有趣的事情,如测试本身。
  19. Edit: i wouldn't use TDD at this stage. By definition, TDD will need all tests present before the changes are in place so you will have failing tests all over the place as you add new testSuites to cover classes that you are working on. Instead add the new testSuite and then add the individual tests as required so you don't get a lot of noise occurring in your test results for failing tests. And, as Yishai points out, adding the task of learning TDD at this point in time will really slow you down. Put learning TDD as a task to be done when you have some spare time. It's not that difficult.
  20. 编辑:我不会在这个阶段使用TDD。根据定义,TDD将需要在更改到位之前进行所有测试,因此当您添加新的testSuite以覆盖您正在处理的类时,您将在整个地方进行失败的测试。而是添加新的testSuite,然后根据需要添加单个测试,这样您的测试结果中就不会出现大量噪声,导致测试失败。而且,正如Yishai指出的那样,在这个时间点添加学习TDD的任务将会让你失望。将学习TDD作为您有空余时间的任务。这并不困难。
  21. as a corollary of this you'll need a tool to keep track of the those existing classes where the testSuite exists but where tests have not yet been written to cover the other member functions in the class. This way you can keep track of where your test coverage has holes. I'm talking at a high level here where you can generate a list of classes and specific member functions where no tests currently exist. A standard naming convention for the tests and testSuites will greatly help you here.
  22. 作为推论,你需要一个工具来跟踪testSuite存在的那些现有类,但是还没有编写测试来覆盖类中的其他成员函数。通过这种方式,您可以跟踪测试覆盖范围的漏洞。我在这里高层谈论,你可以生成一个类列表和特定的成员函数,当前没有测试。测试和testSuite的标准命名约定将极大地帮助您。

I'll add more points as I think of them.

我会想到它们会增加更多的积分。

HTH

HTH

#2


6  

You should get yourself a copy Working Effectively with Legacy Code. This will give you good guidance in how to introduce tests into code that is not written to be tested.

您应该获得一份有效使用旧版代码的副本。这将为您提供有关如何将测试引入未编写的代码的良好指导。

TDD is great, but you do need to start with just putting existing code under test to make sure that changes you make don't change existing required behavior while introducing changes.

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

However, introducing TDD now will slow you down a lot before you get back going, because retrofitting tests, even only in the area you are changing, is going to get complicated before it gets simple.

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

#3


5  

Just to add to the other excellent answers, I'd agree that going from 0% to 100% coverage in one go is unrealistic - but that you should definitely add unit tests every time you fix a bug.

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

You say that there are quite a lot of bugs and unhappy customers - I'd be very positive about incorporating strict TDD into the bugfixing process, which is much easier than implementing it overall. After all, if there really is a bug there that needs to be fixed, then creating a test that reproduces it serves various goals:

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

  • It's likely to be a minimal test case to demonstrate that there really is an issue
  • 它可能是一个最小的测试用例,可以证明确实存在问题
  • With confidence that the (currently failing) test highlights the reported problem, you'll know for sure if your changes have fixed it
  • 有信心(当前失败的)测试突出显示报告的问题,您将确定您的更改是否已修复它
  • It will forever stand as a regression test that will prevent this same issue recurring in future.
  • 它将永远作为回归测试,以防止将来再次出现同样的问题。

Introducing tests to an existing project is difficult and likely to be a long process, but doing them at the same time as fixing bugs is such an ideal time to do so (parallel to introducing tests gradually in a "normal" sense) that it would be a shame not to take that chance and make lemonade from your bug reports. :-)

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

#4


3  

From a planning perspective, I think you have three basic choices:

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

  1. take a cycle to retrofit the code with unit tests
  2. 用一个循环来用单元测试来改造代码
  3. designate part of the team to retrofit the code with unit tests
  4. 指定团队的一部分,通过单元测试来改进代码
  5. introduce unit tests gradually as you work on the code
  6. 在处理代码时逐步引入单元测试

The first approach may well last a lot longer than you anticipate, and your visible productivity will take a hit. If you use it, you will need to get buy-in from all your stakeholders. However, you might use it to kickstart the process.

第一种方法可能会持续比您预期的更长的时间,并且您的可见生产力将受到打击。如果您使用它,您将需要获得所有利益相关者的支持。但是,您可以使用它来启动该过程。

The problem with the second approach is that you create a distinction between coders and test writers. The coders will not feel any ownership for test maintenance. I think this approach is worth avoiding.

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

The third approach is the most organic, and it gets you into test-driven development from the get go. It may take some time for a useful body of unit tests to accumulate. The slow pace of test accumulation might actually be an advantage in that it gives you time to get good at writing tests.

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

All things considered, I think I'd opt for a modest sprint in the spirit of approach 1, followed by a commitment to approach 3.

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

For the general principles of unit testing I recommend the book xUnit Test Patterns: Refactoring Test Code by Gerard Meszaros.

对于单元测试的一般原则,我推荐Gerard Meszaros出版的“xUnit测试模式:重构测试代码”一书。

#5


2  

I've used PHPUnit with good results. PHPUnit, like other JUnit-derived projects, requires that code to be tested be organized into classes. If your project is not object-oriented, then you'll need to start refactoring non-procedural code into functions, and functions into classes.

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

I've not personally used a JavaScript framework, though I would image that these frameworks would also require that your code be structured into (at least) callable functions if not full-blown objects.

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

For testing GUI applications, you may benefit from using Selenium, though a checklist written by a programmer with good QA instincts might work just fine. I've found that using MediaWiki or your favorite Wiki engine is a good place to store checklists and related project documentation.

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

#6


0  

Implementing a framework is in most cases a complex task because you kinda start rebuilding your old code with some new solid framework parts. Those old parts must start to communicate with the framework. The old parts must receive some callbacks and returnstates, the old parts must then somehow point that out to the user and in fact you suddenly have 2 systems to test.

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

If you say that you application itself isn't that complex but it has become due to lack of testing it might be a better option to rebuild the application. Put some common frameworks like Zend to the test, gather your requirements, find out if the tested framework suits for the requirements and decide if it's usefull to start over.

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

I'm not very sure of unit testing, but NetBeans has a built-in unit testing suite.

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

#7


0  

If the code is really messy, it's possible that it will be very hard to do any unit testing. Only sufficiently loosely coupled and sufficiently well designed components can be unit tested easily. However, functional testing may be a lot easier to implement in your case. I would recommend taking a look at Selenium. With this framework, you will be able to test your GUI and the backend at the same time. However, most probably, it won't help you catch the bugs as well as you could with unit testing.

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

#8


0  

Maybe this list will help you and your mates to re-structure everything:

也许这个列表可以帮助你和你的伙伴重新构建一切:

  1. Use UML, to design and handle exceptions (http://en.wikipedia.org/wiki/Unified_Modeling_Language)
  2. 使用UML来设计和处理异常(http://en.wikipedia.org/wiki/Unified_Modeling_Language)
  3. Use BPMS, to design your work-flow so you won't struggle (http://en.wikipedia.org/wiki/Business_process_management)
  4. 使用BPMS来设计您的工作流程,这样您就不会挣扎(http://en.wikipedia.org/wiki/Business_process_management)
  5. Get a list of php frameworks which also support javascript backends (e.g. Zend with jQuery)
  6. 获取一个也支持javascript后端的php框架列表(例如Zend with jQuery)
  7. Compare these frameworks and take the one, which matches the most to your project desgin and the coding structure used before
  8. 比较这些框架并采用与您的项目设计和之前使用的编码结构最匹配的框架
  9. You should may be consider using things like ezComponents and Dtrace for debugging and testing
  10. 您应该考虑使用ezComponents和Dtrace之类的东西进行调试和测试
  11. Do not be afraid of changes ;)
  12. 不要害怕改变;)

#9


0  

For GUI testing you may want to take a look at Selenium (as Ignas R pointed out already) OR you may wanna take a look at this tool as well: STIQ.

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

Best of luck!

祝你好运!

#10


0  

In some cases, doing automatic testing may not be such a good idea, especially when the code base is dirty and PHP mixes it's behavior with Javascript.

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

It could be better to start with a simple checklist (with links, to make it faster) of the tests that should be done (manually) on the thing before each delivery.

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

When coding in a 3 years old minefield, better protect yourself with many error checking. The 15 minutes spent writing THE proper error message for each case will not be lost.

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

Use the bridging method: bridge ugly lengthy function fold() with a call to fnew() which is a wrapper around some clean classes, call both fold and fnew and compare result, log differences, throw the code into production and wait for your fishes. When doing this, always use one cycle for refactoring, anOTHER cycle for changing result (do not even fix bugs in old behavior, just bridge it).

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

#11


0  

I agree with KOHb, Selenium is a must !

我同意KOHb,Selenium是必须的!

Also have a look at PHPure,

还看看PHPure,

Their software records the inputs and outputs from a working php website, and then automatically writes phpunit tests for functions that do not access external sources (db, files etc..).

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

It's not a 100% solution, but it's a great start

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

#1


6  

G'day,

天儿真好,

Edit: I've just had a quick look through the first chapter of "The Art of Unit Testing" which is also available as a free PDF at the book's website. It'll give you a good overview of what you are trying to do with a unit test.

编辑:我刚刚浏览了“单元测试艺术”的第一章,该书也可以在本书的网站上以免费PDF格式获得。它将为您提供一个很好的概述,您正在尝试使用单元测试。

I'm assuming you're going to use an xUnit type framework. Some initial high-level thoughts are:

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

  1. Edit: make sure that everyone is is agreement as to what constitutes a good unit test. I'd suggest using the above overview chapter as a good starting point and if needed take it from there. Imagine having people run off enthusiastically to create lots of unit tests while having a different understanding of what a "good" unit test. It'd be terrible for you to out in the future that 25% of your unit tests aren't useful, repeatable, reliable, etc., etc..
  2. 编辑:确保每个人都同意什么是良好的单元测试。我建议使用上面的概述章作为一个很好的起点,如果需要,可以从那里开始。想象一下,让人们热情地跑去创造大量的单元测试,同时对“好”的单元测试有不同的理解。对你来说,25%的单元测试没有用,可重复,可靠等等,这对你来说太可怕了。
  3. add tests to cover small chunks of code at a time. That is, don't create a single, monolithic task to add tests for the existing code base.
  4. 添加测试以一次覆盖小块代码。也就是说,不要创建单个整体任务来为现有代码库添加测试。
  5. modify any existing processes to make sure new tests are added for any new code written. Make it a part of the review process of the code that unit tests must be provided for the new functionality.
  6. 修改任何现有进程以确保为编写的任何新代码添加新测试。使其成为代码审查过程的一部分,必须为新功能提供单元测试。
  7. extend any existing bugfix processes to make sure that new tests are created to show presence and prove the absence of the bug. N.B. Don't forget to rollback your candidate fix to introduce the bug again to verify that it is only that single patch that has corrected the problem and it is not being fixed by a combination of factors.
  8. 扩展任何现有的错误修复过程,以确保创建新的测试以显示存在并证明没有错误。注:不要忘记回滚您的候选修复程序再次引入该错误,以验证它只是纠正问题的单个修补程序,而不是由多种因素组合修复。
  9. Edit: as you start to build up the number of your tests, start running them as nightly regression tests to check nothing has been broken by new functionality.
  10. 编辑:当您开始构建测试数量时,开始将它们作为夜间回归测试运行,以检查新功能是否已破坏任何内容。
  11. make a successful run of all existing tests and entry criterion for the review process of a candidate bugfix.
  12. 为候选bugfix的审查过程成功运行所有现有测试和进入标准。
  13. Edit: start keeping a catalogue of test types, i.e. test code fragments, to make the creation of new tests easier. No sense in reinventing the wheel all the time. The unit test(s) written to test opening a file in one part of the code base is/are going to be similar to the unit test(s) written to test code that opens a different file in a different part of the code base. Catalogue these to make them easy to find.
  14. 编辑:开始保留测试类型的目录,即测试代码片段,以便更轻松地创建新测试。没有任何意义重新发明*。为测试在代码库的一部分中打开文件而编写的单元测试将类似于写入测试代码的单元测试,该测试代码在代码库的不同部分中打开不同的文件。将这些目录编目以便于查找。
  15. Edit: where you are only modifying a couple of methods for an existing class, create a test suite to hold the complete set of tests for the class. Then only add the individual tests for the methods you are modifying to this test suite. This uses xUnit termonology as I'm now assuming you'll be using an xUnit framework like PHPUnit.
  16. 编辑:您只修改现有类的几个方法,创建一个测试套件来保存该类的完整测试集。然后,仅将要修改的方法的各个测试添加到此测试套件中。这使用xUnit termonology,因为我现在假设您将使用像PHPUnit这样的xUnit框架。
  17. use a standard convention for the naming of your test suites and tests, e.g. testSuite_classA which will then contain individual tests like test__test_function. For example, test_fopen_bad_name and test_fopen_bad_perms, etc. This helps minimise the noise when moving around the code base and looking at other people's tests. It also has then benefit of helping people when they come to name their tests in the first place by freeing up their mind to work on the more interesting stuff like the tests themselves.
  18. 使用标准约定来命名测试套件和测试,例如: testSuite_classA然后将包含各个测试,如test__test_function。例如,test_fopen_bad_name和test_fopen_bad_perms等。这有助于最小化在代码库中移动并查看其他人的测试时的噪音。它还有助于帮助人们在他们首先命名他们的测试时,通过释放他们的思想来处理更有趣的事情,如测试本身。
  19. Edit: i wouldn't use TDD at this stage. By definition, TDD will need all tests present before the changes are in place so you will have failing tests all over the place as you add new testSuites to cover classes that you are working on. Instead add the new testSuite and then add the individual tests as required so you don't get a lot of noise occurring in your test results for failing tests. And, as Yishai points out, adding the task of learning TDD at this point in time will really slow you down. Put learning TDD as a task to be done when you have some spare time. It's not that difficult.
  20. 编辑:我不会在这个阶段使用TDD。根据定义,TDD将需要在更改到位之前进行所有测试,因此当您添加新的testSuite以覆盖您正在处理的类时,您将在整个地方进行失败的测试。而是添加新的testSuite,然后根据需要添加单个测试,这样您的测试结果中就不会出现大量噪声,导致测试失败。而且,正如Yishai指出的那样,在这个时间点添加学习TDD的任务将会让你失望。将学习TDD作为您有空余时间的任务。这并不困难。
  21. as a corollary of this you'll need a tool to keep track of the those existing classes where the testSuite exists but where tests have not yet been written to cover the other member functions in the class. This way you can keep track of where your test coverage has holes. I'm talking at a high level here where you can generate a list of classes and specific member functions where no tests currently exist. A standard naming convention for the tests and testSuites will greatly help you here.
  22. 作为推论,你需要一个工具来跟踪testSuite存在的那些现有类,但是还没有编写测试来覆盖类中的其他成员函数。通过这种方式,您可以跟踪测试覆盖范围的漏洞。我在这里高层谈论,你可以生成一个类列表和特定的成员函数,当前没有测试。测试和testSuite的标准命名约定将极大地帮助您。

I'll add more points as I think of them.

我会想到它们会增加更多的积分。

HTH

HTH

#2


6  

You should get yourself a copy Working Effectively with Legacy Code. This will give you good guidance in how to introduce tests into code that is not written to be tested.

您应该获得一份有效使用旧版代码的副本。这将为您提供有关如何将测试引入未编写的代码的良好指导。

TDD is great, but you do need to start with just putting existing code under test to make sure that changes you make don't change existing required behavior while introducing changes.

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

However, introducing TDD now will slow you down a lot before you get back going, because retrofitting tests, even only in the area you are changing, is going to get complicated before it gets simple.

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

#3


5  

Just to add to the other excellent answers, I'd agree that going from 0% to 100% coverage in one go is unrealistic - but that you should definitely add unit tests every time you fix a bug.

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

You say that there are quite a lot of bugs and unhappy customers - I'd be very positive about incorporating strict TDD into the bugfixing process, which is much easier than implementing it overall. After all, if there really is a bug there that needs to be fixed, then creating a test that reproduces it serves various goals:

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

  • It's likely to be a minimal test case to demonstrate that there really is an issue
  • 它可能是一个最小的测试用例,可以证明确实存在问题
  • With confidence that the (currently failing) test highlights the reported problem, you'll know for sure if your changes have fixed it
  • 有信心(当前失败的)测试突出显示报告的问题,您将确定您的更改是否已修复它
  • It will forever stand as a regression test that will prevent this same issue recurring in future.
  • 它将永远作为回归测试,以防止将来再次出现同样的问题。

Introducing tests to an existing project is difficult and likely to be a long process, but doing them at the same time as fixing bugs is such an ideal time to do so (parallel to introducing tests gradually in a "normal" sense) that it would be a shame not to take that chance and make lemonade from your bug reports. :-)

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

#4


3  

From a planning perspective, I think you have three basic choices:

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

  1. take a cycle to retrofit the code with unit tests
  2. 用一个循环来用单元测试来改造代码
  3. designate part of the team to retrofit the code with unit tests
  4. 指定团队的一部分,通过单元测试来改进代码
  5. introduce unit tests gradually as you work on the code
  6. 在处理代码时逐步引入单元测试

The first approach may well last a lot longer than you anticipate, and your visible productivity will take a hit. If you use it, you will need to get buy-in from all your stakeholders. However, you might use it to kickstart the process.

第一种方法可能会持续比您预期的更长的时间,并且您的可见生产力将受到打击。如果您使用它,您将需要获得所有利益相关者的支持。但是,您可以使用它来启动该过程。

The problem with the second approach is that you create a distinction between coders and test writers. The coders will not feel any ownership for test maintenance. I think this approach is worth avoiding.

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

The third approach is the most organic, and it gets you into test-driven development from the get go. It may take some time for a useful body of unit tests to accumulate. The slow pace of test accumulation might actually be an advantage in that it gives you time to get good at writing tests.

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

All things considered, I think I'd opt for a modest sprint in the spirit of approach 1, followed by a commitment to approach 3.

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

For the general principles of unit testing I recommend the book xUnit Test Patterns: Refactoring Test Code by Gerard Meszaros.

对于单元测试的一般原则,我推荐Gerard Meszaros出版的“xUnit测试模式:重构测试代码”一书。

#5


2  

I've used PHPUnit with good results. PHPUnit, like other JUnit-derived projects, requires that code to be tested be organized into classes. If your project is not object-oriented, then you'll need to start refactoring non-procedural code into functions, and functions into classes.

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

I've not personally used a JavaScript framework, though I would image that these frameworks would also require that your code be structured into (at least) callable functions if not full-blown objects.

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

For testing GUI applications, you may benefit from using Selenium, though a checklist written by a programmer with good QA instincts might work just fine. I've found that using MediaWiki or your favorite Wiki engine is a good place to store checklists and related project documentation.

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

#6


0  

Implementing a framework is in most cases a complex task because you kinda start rebuilding your old code with some new solid framework parts. Those old parts must start to communicate with the framework. The old parts must receive some callbacks and returnstates, the old parts must then somehow point that out to the user and in fact you suddenly have 2 systems to test.

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

If you say that you application itself isn't that complex but it has become due to lack of testing it might be a better option to rebuild the application. Put some common frameworks like Zend to the test, gather your requirements, find out if the tested framework suits for the requirements and decide if it's usefull to start over.

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

I'm not very sure of unit testing, but NetBeans has a built-in unit testing suite.

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

#7


0  

If the code is really messy, it's possible that it will be very hard to do any unit testing. Only sufficiently loosely coupled and sufficiently well designed components can be unit tested easily. However, functional testing may be a lot easier to implement in your case. I would recommend taking a look at Selenium. With this framework, you will be able to test your GUI and the backend at the same time. However, most probably, it won't help you catch the bugs as well as you could with unit testing.

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

#8


0  

Maybe this list will help you and your mates to re-structure everything:

也许这个列表可以帮助你和你的伙伴重新构建一切:

  1. Use UML, to design and handle exceptions (http://en.wikipedia.org/wiki/Unified_Modeling_Language)
  2. 使用UML来设计和处理异常(http://en.wikipedia.org/wiki/Unified_Modeling_Language)
  3. Use BPMS, to design your work-flow so you won't struggle (http://en.wikipedia.org/wiki/Business_process_management)
  4. 使用BPMS来设计您的工作流程,这样您就不会挣扎(http://en.wikipedia.org/wiki/Business_process_management)
  5. Get a list of php frameworks which also support javascript backends (e.g. Zend with jQuery)
  6. 获取一个也支持javascript后端的php框架列表(例如Zend with jQuery)
  7. Compare these frameworks and take the one, which matches the most to your project desgin and the coding structure used before
  8. 比较这些框架并采用与您的项目设计和之前使用的编码结构最匹配的框架
  9. You should may be consider using things like ezComponents and Dtrace for debugging and testing
  10. 您应该考虑使用ezComponents和Dtrace之类的东西进行调试和测试
  11. Do not be afraid of changes ;)
  12. 不要害怕改变;)

#9


0  

For GUI testing you may want to take a look at Selenium (as Ignas R pointed out already) OR you may wanna take a look at this tool as well: STIQ.

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

Best of luck!

祝你好运!

#10


0  

In some cases, doing automatic testing may not be such a good idea, especially when the code base is dirty and PHP mixes it's behavior with Javascript.

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

It could be better to start with a simple checklist (with links, to make it faster) of the tests that should be done (manually) on the thing before each delivery.

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

When coding in a 3 years old minefield, better protect yourself with many error checking. The 15 minutes spent writing THE proper error message for each case will not be lost.

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

Use the bridging method: bridge ugly lengthy function fold() with a call to fnew() which is a wrapper around some clean classes, call both fold and fnew and compare result, log differences, throw the code into production and wait for your fishes. When doing this, always use one cycle for refactoring, anOTHER cycle for changing result (do not even fix bugs in old behavior, just bridge it).

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

#11


0  

I agree with KOHb, Selenium is a must !

我同意KOHb,Selenium是必须的!

Also have a look at PHPure,

还看看PHPure,

Their software records the inputs and outputs from a working php website, and then automatically writes phpunit tests for functions that do not access external sources (db, files etc..).

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

It's not a 100% solution, but it's a great start

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