"Michael B. Trausch" <mike$#at^&[EMAIL PROTECTED]> writes:
> Ben Finney wrote: > > Jean-Paul Calderone <[EMAIL PROTECTED]> writes: > > > >> 1) Write unit tests for your code. Keep writing unit tests until > >> you have some that _don't pass_. Then fix your code so that they > >> do. When you do further development, write the tests first, then > >> implement the code that makes them pass. > > > > Hear hear. > > > > Be advised, though, that attempting to apply unit tests to code > > that wasn't designed with testing in mind may very quickly reveal > > a poor design. [0] If you can't easily test pieces of the code > > independently, you probably haven't written those pieces to be > > loosely coupled and well-defined. > > > > I will whole-heartedly admit that my code is probably poorly > designed. *shrug* Though, I *do* try to write everything in such a > way as to be able to easily re-use it later. The trick is to write pieces that are small and loosely-coupled, so that small pieces of code (not just entire modules) can be re-used without being re-written. Test-driven development helps with this, because a small, loosely-coupled piece of code is easy to test, so you will gravitate toward that style. > Besides, I am lazy... reuse certainly serves my needs there! :-) The programming virtues espoused by Larry Wall continue to hold true :-) > I think I have more to learn on the concept of unit-testing. > I have never seen a group push the idea so hard. Writing each test before the functional code is not a new idea, but Python makes it trivially easy to do, so the excuses for not doing it are much weaker and easier to ridicule :-) > I have read about unit testing before, and even written tests (in > other languages) to test modules of library code that I put together > once, but that was about it. Here's an article that goes through the concepts, and happens to use Python. <URL:http://www.onlamp.com/pub/a/python/2004/12/02/tdd_pyunit.html> > I need to, I think, get more "into" the concept, though. It isn't > something that I am able to just whip out and go "Hey, a widget unit > test! And it works!" probably because of my own lack of practice. One thing to note is that UI widgets shouldn't be the main thing you're testing. You need to write code that can be easily tested independent of everything else, because that way you can know that it works and move on to other things quickly, building on it as a foundation. UI widgets should be as dumb as possible, because they don't make a whole lot of sense by themselves except in the dumbest sense. Every part of your program that actually does something interesting with data or resources should be utterly independent of any UI widgets. *That* is the code that you need to get right, so that should be riddled with tests. Your widgets should be plugging into code that dumbly passes the data to the well-tested, UI-independent code that does work with that data; and the widgest should be getting their data from such UI-independent outputs. This is one aspect of "loose coupling": the code talks along a very narrow, well-defined, simple interface to other parts of the code. UI code especially is prone to change entirely independent of the desired functionality. for this reason, it's vital that you *can* change the functionality and UI code each without needing to change the other. The same principle applies along any interface between parts of code that can be expected to change independent of each other: loosely couple them together, with narrow well-defined interfaces. You may have heard of the "Model, View, Controller" pattern. This is a design pattern that emphasises a loose coupling between the UI (the "controller") and the data model, by abstracting each to the other via a simple "view" interface module. That way, each of the Controller and the Model can be oblivious to the most common changes in the other, even when those changes make for complex code, because the View they interact with stays simple and doesn't need to change. <URL:http://en.wikipedia.org/wiki/Model-view-controller> The reason test-driven development is so useful here is that, in order to write a test for something *before* it exists, you must think about how that piece of code will interact with the rest of the code. You must, in other words, design its interface before writing its code. This is excellent, because it means you're focussing on exactly the thing that will help to keep your overall design loosely coupled. Then, after you have a test that interacts with this interface, all you need to do is write the simplest code to satisfy that interface. The temptation to write clever, complex code is reduced, because you're now interested in satisfying the external test, not in treating this piece of code as an awesome complex machine ignoring the rest of the code. Good luck with getting test infected :-) <URL:http://c2.com/cgi/wiki?TestInfected> -- \ "I bought a self learning record to learn Spanish. I turned it | `\ on and went to sleep; the record got stuck. The next day I | _o__) could only stutter in Spanish." -- Steven Wright | Ben Finney -- http://mail.python.org/mailman/listinfo/python-list