|
[I
don't mean to start a Unit Testing religious war, but here goes... :-)
]
bruno wrote: Paulo Soares wrote: This is exactly backwards. Really good programmers (those who always get it right the first time, and who never make any mistakes) don't need unit tests at all. It's the rest of us (those who occasionally mis-type something, or who will add code to one class, but forget to add the corresponding code to another class) who need unit tests. They help us produce good code, even though we are not perfect programmers. A primary purpose of unit tests is to complain immediately when something that used to work, doesn't work any more. Having that kind of safety net gives me all kinds of freedom: freedom to experiment with various solutions to a single problem; freedom to improve my design whenever I discover a better way; freedom to optimize my code as needed -- all without fear of inadvertently breaking something. Having said that, some kinds of code are harder to test than others. For example, GUI components are notoriously difficult to test, and many programmers decide that testing the components themselves simply isn't worthwhile. One successful approach to this problem is to rigorously separate the Data Model and Business Rules from the UI -- keeping the UI layer as thin as possible, by making sure that the GUI components simply reflect the Data Model, and do not perform any data processing themselves. The Data Model classes can then be tested extensively, while the GUI components are tested occasionally, by visual inspection. After a few months working with iText, I would include PDF output among those things that are quite difficult to test. But you can still take a similar approach of separating the Data Model from the UI (the PDF document). For example, my reports are the result of a rather complex traversal of ReportRequests, ReportDefinitions, Layouts, Items, Sections, ReportingTrees, Columns, etc. All of these are business classes, and none of them have any dependencies on the iText library itself. And all of them are backed by exhaustive unit tests. The report process generates a collection representing the "leaf-nodes" of the traversal algorithm. These are the pieces of information that will actually be included in the final report. That collection is also tested extensively. Finally, I have a PdfDocument class whose only responsibility is to render that leaf-node collection as a PDF document. This class, together with a few helper classes in the same package, are the only classes in my code base that know anything about iText. The unit tests for this package just check to make sure that the expected PDF files were created on disk, and that their sizes are reasonable (say, within 10% of the last "approved" report size). When I make an expected change to the PDF output, I check the resulting file in Adobe, and then adjust the expected report size appropriately. That's it. Now, if I change one of my model classes, and the change erroneously excludes a section from the final report, I know about it immediately. Furthermore, I know exactly which change caused the problem, because the tests all passed when I ran them two minutes ago. Of course, "Test-Driven Development" has many other benefits, but this post is already too long, and probably too far off-topic. And I'm not a very good programmer anyway -- so I'll stop now. :-) -Chip Whitmer |
