I've been recently assigned to a project, where I need to write regression tests, i.e. unit, functional, and integration tests, for client developers. The project was already half way through, and I was told that the client developers were too busy with writing code to write tests for their code. So they wanted someone from ThoughtWorks to take care of it.
Before I took off from London, I checked out their code, and had a quick look. The first impression was that the code was highly coupled with external system (messaging, cache, and grid etc), and multi-threaded. But there were no tests for these aspects at all. A quick browse already revealed a few bugs. No wonder they are keen to have tests in place.
Three days into writing tests, it has quickly come to a point where it becomes so hard, if not impossible to write tests without changing the code. The problems make writing tests hard include over use of singletons (most of the major classes are singletons), complicated external systems get instantiated inside a class, rather than injected(often, more than three systems get instantiated in one class, it takes so much effort to mock out all of them, and yet still can not inject them.), overly layered, and complicated private method(me and my pair think it is a code smell if you feel the need to test your private method, your class is probably doing too much. To test a private method, you probably have to resort to reflection) . All these problems make the testability of the code very poor. Clearly the solution is architected without testability in mind. People think they should concentrate on writing code, and hire a test-writing expert afterwards, the problem will be solved. The truth is test can not be an after thought; otherwise the code will have no testability. I think it is one reason why TDD (Test Driven Development) makes sense. Again and again it has dawned on me, singleton is evil, it should not be documented as a legitimate pattern. It does more harm than good as a documented pattern.
My pair, Neal Ford, has realized this as well. He has offered to give the client a introduction to test writing techniques, before he leaves this project, in hope we could piggyback the idea of putting testability first. It will be our first attempt to sell the idea. And hopefully we can win people's minds and hearts over next a few months. This is the only way I can be of most value to them though.
-------------------------------------------------------------------------------------------------------
(更正了一个错别字,regression tests 应翻译成“渐退式测试“, 而不是“进退式测试”。两字差别很大,所以改正后重新发帖。)
最近我加入了一个新的项目。在这个项目上我需要为客户的开发者写”渐退式测试regression tests)”. 也就是由单元测试,功能测试,和集成测试多层测试组成的测试。我被告知客户的开发者们过于忙于写代码,以至于没有时间给他们自己的代码写测试。所以他们希望ThoughtWorks的人能把这个搞定。
从伦敦出发前,我快速的浏览了一眼他们的代码。第一印象是代码和外部的系统(messing, cache, 和 grid系统等)耦合度很高,并且是多线程的代码。但是这些重要的方面都没有测试代码。这样简单的浏览已经发现了数个bugs.怪不得他们像有些测试代码呢。
写了三天的测试后,很快就到了一个临界点---在不改他们的代码的前提下,写测试已经变得非常困难,如果不是不可能的话。使测试难写的主要原因有大量的singleton; 在class内部进行多个复杂的外部系统的初始化,而不是传递进 --要写这样程序的测试,先不提如何将这些“被依赖的外部系统注射“(dependency injection)进去, mock这些系统的代码就会非常繁琐;冗余的多层结构,和复杂的private method(我和我的搭档认为如果你觉得有测试你的private method的需要,这就是一个code smell. 因为这很可能表明你的class在做太多的问题。你大概必须要依靠reflection来测试一个private method). 这些问题使的代码的可测试性很差。很明显系统是设计的时候,是没有将可测试性考虑在内的。很多人认为他们需要集中精力写代码,在这之后雇一个写测试的专家,问题就解决了。可真实的情况是测试是不能作为马后炮的,否则代码就没有可测试性。我想这也是测试开发(TDD, test driven development)和理性的一个原因。同时一个再三的证明singleton是个恶魔, 不应该作为一个设计模版。作为一个设计模版,它的危害性大过了它的益处。
我的搭档,Neal Ford, 也认识到了这个问题。他已经向客户提出了做一堂测试代码写作技巧的讲座,希望讲座的同时我们可以推销将可测试性放在第一的注意。这将是我们的第一个推销尝试。希望我们可以在下面的数个月里逐渐赢得人们的赞同。只有这样,我的工作才能真正为他们带来价值。
Recent Comments