From: Jacob Fugal Date: 2006-07-07T09:21:45+09:00 Subject: Re: Float#==. Legacy? On 7/6/06, Matthew Smillie wrote: > On Jul 6, 2006, at 21:49, Jacob Fugal wrote: > > You are right, that choosing the wrong delta for assert_in_delta can > > be just as problematic as using Float#==. But I don't think that > > throwing away assert_in_delta and using assert_equal with a parallel > > calculation is the answer. In the trivial example you gave, it's fine, > > since you've got one operation. But what if the method under test > > performs many operations, due to complicated business rules? > > (Hopefully those rules are factored out into their own tested methods, > > but that doesn't stop them from being part of the behavior of that > > method). Should we duplicate the entire process in the test? That > > seems wasteful and error prone. I'll stick with assert_in_delta and an > > expected value. > > I didn't (and wouldn't) suggest abandoning assert_in_delta. What I > was discussing was the idea to push that functionality (which is > specific to certain situations) into the general Float#== method, > where, for a number of reasons, it's inappropriate. Ah, ok, we're on the same page for that discussion then. I was initially intrigued by the idea, but your post made it obvious that it doesn't belong there, primarily -- in my mind -- because of the lack of a "universal" delta. And the syntax of == doesn't make it very convenient to specify the delta. :) > As for the example of "what if the method uses other really > complicated methods?" though, aren't those other methods unit tested, > likely on the same general input domain? If so, and they pass to > your satisfaction, then why not simply use them in the calculation of > the test value for the encompassing method - errors which arise from > the subsidiary methods should be caught in the unit tests for those > methods, so there's no loss of generality in the testing. To extend > the trivial example from before: > > def foo(a, b) > # arbitrary floating point math > a * (some_method(a) + other_method(a, b)) > end > > # test setup - these should all be values for which > # you're confident the implementation is adequate. > a = 22.0 > b = SomeCompany.new("test") > c = some_method(a) > d = other_method(a, b) > > # replicate the fundamental logic of the method being tested here. > calc_result = a * (c + d) This is exactly what I was getting at though. You've basically replicated the entire function in the test itself! I don't think that's the point of having the unit test. :) > What if the variation you're seeing isn't a floating point error, but > something incorrect in your logic somewhere? Say, a rounding error > in a database field, or a problem with serialisation to/from SOAP. > What's the risk of that? What's the impact? If you're only > concerned about accuracy within some delta, then you only need to > test to that delta. It's just that sometimes that delta might be 0. All good points. That's why I stress the importance of using the appropriate delta. For instance, if you're working with currency represented as floats (bad monkey!) then a delta of 0.001 should be plenty sufficient. If I'm actually doing floating point math however, I probably want to use a very small delta to make sure my calculations aren't actually off. > So, there are lots of times where assert_in_delta is the best thing > to do (ensuring two different methods or computation agree to some > degree, developer time, simplicity), but that doesn't meant that > Float#== should take on that functionality. Agreed. Jacob Fugal