From: David Chelimsky Date: 2007-01-24T14:05:37+09:00 Subject: Re: I don't get rspec On 1/23/07, Eric Hodel wrote: > On Jan 23, 2007, at 16:26, James Edward Gray II wrote: > > On Jan 23, 2007, at 6:10 PM, Joe Van Dyk wrote: > >> What's wrong with zentest, specifically? > > > > You will probably understand better by watching the movie, but > > zentest encourages you to make a test case for each class and a > > test method for each method. > > Which will match up 1:1 if you factor your code well. Eric, I realize that you might have been put on the defensive here, but the suggestion that 1:1 is the only natural conclusion of well factored code denies a world of experience. In my own experience, the ratio of test cases to classes usually starts off close to 1:1, but as a project evolves it naturally moves away from that. If you see that a class is growing, for example, it is common to start refactoring out methods into new classes as those classes make themselves apparent. Some people will add new tests for the new class as a matter of course. If you do that, then you are testing the same code in two different tests. Multiply that over a large system and you're increasing the time it takes your test suites to run exponentially. Slower test suites get run less often, providing less timely feedback. Also, 1:1 mapping means that every time you want to refactor you are burdened with refactoring your tests. 1:1 as a policy has a tendency to push people towards doing less refactoring and leaving code in a state that less well factored than they might envision. Others are satisfied that the new class is already tested through the classes that are using it. The risk they run is that tests get further and further away from the code they are testing, and problems become progressively difficult to isolate. Which is right? Neither 100% of the time. The skill is in finding the right balance in each different situation and understanding how to make good decisions about when new tests resulting from refactoring is a good idea and when it's not. > > > BDD teaches that these decisions are pretty arbitrary. > > I don't use BDD because I already have my tests broken up by units of > behavior. I call them methods. > > BDD presents a method of thinking about test design to help you focus > on better object design and object modeling. Unit testing doesn't > have this method of thinking built-in, you have to discover it. I'm not sure I understand the distinction you're trying to make here. TDD/BDD is all about discovery. > (Although it makes itself evident if you pay attention to how > difficult it is to test something.) > > > The true goal of testing is to test the "behaviors" of your > > object. If that means interacting with five methods or just one > > possible call sequence of a method that has several, that's what > > you should really be testing. > > I think there are two true goals of testing. One is to enumerate > your edge cases so each one behaves as you expect. Another is to get > feedback about how well you've designed your program. Both are > equally important. Agree. > If you want to write specifications to enumerate your edge cases, > great. However, if you've factored poorly neither BDD nor TDD will > give you small, concise tests nor a small, concise implementation. Agree, though I do believe that writing the tests first helps to push you in the right direction. > > > What do if you need to work with two classes at one to test something? > > Then your classes are probably coupled too tightly. Let's say you have a Money class that handles things like rounding, math, conversions, etc. This is all very well tested. Now you are building an Account class that interacts with an instance of Money. Would you mock that out in every Account test? > > > This class and method organization is also encourages you to use so- > > so names for your tests at best. If you have a Calendar class and > > a TestCalendar, that's pretty much saying the same thing twice (a > > violation of DRY) and it doesn't tell you much. BDD encourages you > > to actually express what you are testing with your naming. This > > really helps you focus on the goal of the process and is much less > > arbitrary. > > Mapping tests to classes 1:1 is a sign of proper design. Again, I disagree. 1:1 mapping is a sign that you are good at following policy, nothing more. If I write a giant class that has 50 methods with a single test case with 50 corresponding test methods I've met 1:1, but I still probably have a shitty design. If I have some other, looser ratio of tests/classes and every time I need to add features to my app it takes 10 times what I expect it to, I probably have a shitty design. On the flip side, if I have a design that is easy for me or any of my colleagues to extend as business requirements change, then I have a good design. For that to happen there is probably good test coverage, but I really don't think that 1:1 mapping has much to do with it. But that's just me. Cheers, David > Your > implementation's names should reflect the behavior implemented > within. If you have to give different names to your tests and your > implementation you've probably named your implementation poorly. > Instead you should refactor your implementation so that it can be > named well. > > Read the tutorial on the rspec site: > > http://rspec.rubyforge.org/tutorials/index.html > > The specifications match up with the implementation very well, so the > Stack is probably well-designed > If they didn't, that's a good sign > of code smell. > > (You get the same code smell out of unit testing, it just smells a > little different.) > > -- > Eric Hodel - drbrain@segment7.net - http://blog.segment7.net > > I LIT YOUR GEM ON FIRE! > > >