Re: How do you write tests if you aren't sure what the result should be?
George Dinwiddie <[email protected]>
| Newsgroups | gmane.comp.programming.test-driven-development |
|---|---|
| Organization | iDIA Computing, LLC |
| Message-ID | <[email protected]> |
Amir, On 2/17/13 12:52 PM, Amir Kolsky wrote: > Great job analyzing this, Ron (seriously). > > Thing is, none of it had anything to do with TDD... Look again. >> Now our question here is how to TDD all this. I would do at least this much >> thinking with pencil and paper, which takes less time than it took to write >> this. To TDD the patch of code above, I've got a problem, which is that it >> calls time(). I can't really TDD well that way, because time is always >> weird. Just as we do with a random number, we need to abstract time out, so >> that our test can look like this: >> >> deltaTime = 1.0/30.0 >> assertEquals(15, distanceMoved(deltaTime)) That's what I was talking about when I said, > It sounds like a typical problem of not abstracting the external source > of timing. You should be able to calculate into the future without being > tied to the system clock. Abstracting external systems, even ones as ubiquitous as the system clock, is essential in TDD. - George > > -----Original Message----- > From: [email protected] > [mailto:[email protected]] On Behalf Of Ron Jeffries > Sent: Sunday, February 17, 2013 3:40 AM > To: [email protected] > Subject: Re: [TDD] How do you write tests if you aren't sure what the result > should be? > > Hi Avi . > > On Feb 17, 2013, at 1:03 AM, Avi Kessner <[email protected]> wrote: > >> My comparison was supposed to be regarding the culmative calculation, >> not the per tick calculation. >> >> Ill have to look up when velocity is multiplied vs when it's added. > > > I was supposing that dt is some kind of a time value. I imagined that it > meant "delta time" or "change in time since last time". Its dimensions must > surely be "seconds" or some other time value. I don't know whether you have > set > > I was supposing that x is some kind of position value. I imagined that its > dimensions were "meters" or "pixels", or some other distance value. > > The expression was x += dt. Dimensionally, pixels += seconds, or meters += > seconds. Can't really be right. > > Now what we often do when we animate a penguin -- I mean who doesn't animate > a penguin every now and again -- is reason as follows: > > I suppose I'll get about 30 frames a second; I suppose I'd like him to move > across the screen in about 2 seconds; The way gravity works is you go > constant speed in X but up and down in Y; I plan to get 30 frames a second; > So I'll need 60 frames to move him The part of the screen he'll move across > is about 900 pixels; He has to move 900/60 . uh . 15 pixels every second in > the x direction; . and so on > > Then, having done the math, when we calculate the penguin's x in our draw() > code, called, we guess, every 1/30 second, we can just write: > > x += 15 > > Then the new iPad comes out and our draw() function is called 60 times a > second and poor Pengi zips across so fast that it's no fun. So we reason: > > OK, well, he's moving 15 per tick. But now on the new iPad I get 60 ticks > and he should move about half that. > I should generalize this. > Hm, well, I want him to go 900 pixels in 2 seconds. That's 450 pixels per > second. > Um, maybe if I just read out the actual time since last time I can use that. > So I'll save time in timeThen and read time now and difference them. > the time() function is a float, seconds since long time ago. > > And we write > > draw() > timeNow = time() > dt = timeNow - timeThen > x += 450*dt > timeThen = timeNow > end > > Now our draw() function is independent of frame rate. But wait! what is that > 450*dt??? It seems we just added time to distance and that's supposed to be > wrong. It's ok. look at the dimensional analysis of that statement: > > pixels += (pixels/second)*second > > the seconds cancel and we're adding pixels to pixels if x was in meters, > it'd be meters += (meters/second)*second, so that would be OK too. > > Now our question here is how to TDD all this. I would do at least this much > thinking with pencil and paper, which takes less time than it took to write > this. To TDD the patch of code above, I've got a problem, which is that it > calls time(). I can't really TDD well that way, because time is always > weird. Just as we do with a random number, we need to abstract time out, so > that our test can look like this: > > deltaTime = 1.0/30.0 > assertEquals(15, distanceMoved(deltaTime)) > > This requires us to write > > distanceMoved(float dt) > return 450*dt > end > > which means our draw function needs to be > > draw() > timeNow = time() > dt = timeNow-timeThen > x += distanceMoved(dt) > timeThen = timeNow > end > > Now how might we TDD that whole patch. Honestly unless I was demonstrating > my great TDD powers, I'm not sure I would, but your mission is to > demonstrate great TDD powers. It's darned hard to do in retrospect, when the > code is so easy, but we have to learn to think backwards, so let's pretend > that we are thinking that the draw has to look like that but that we were > being really retentive about TDD, and didn't type it in yet. So we reason, > knowing full well what we want: > > OK, we have a way to compute distanceMoved as a function of a delta-time. > Now we need a way to measure delta time. > So, um, let's have a delta-time function that we call in our draw. Its test > is, um . > > beginTime = 1.5 > initDeltaTime(beginTime) > endTime = 2 > assertEquals(0.5, deltaTime(endTime)) > endTime = 3.5 > assertEquals(1.5, deltaTime(endTime)) > > Hmm, how can we write delta time? Well . > > lastTime = 0.0 > initDeltaTime(float aTime) > lastTime = aTime > end > > float deltaTime(float aTime) > dt = aTime-lastTime > lastTime = atime > return dt > end > > Now the draw() that we have in our head looks like x += > distanceMoved(deltaTime(time()) y += godWhatWillWeDoAboutY(time()) > sprite("penguin", x, y) > > and both the distanceMoved function and the deltaTime function have been > fully TDD'd. Now we do the y function. > Because we've read that article that you posted, we realize that we want a > velocity that isn't constant 450/second, but is instead a function of > gravity. And we know that we want to do that average velocity trick -- after > we understand it, which we might not at the beginning. > > We proceed similarly. Your mission, if you care to, is to follow my > reasoning above, then try to reason similarly as you calculate Y. I don't > know yet what I'd do, because I'm stopping here for now. Unless I decide to > animate a penguin in Codea . > > Hang in there! > > Ron Jeffries > www.XProgramming.com > It's true hard work never killed anybody, but I figure, why take the chance? > -- Ronald Reagan > > > > > > [Non-text portions of this message have been removed] > > > > ------------------------------------ > > Yahoo! Groups Links > > > > > > ------------------------------------ > > Yahoo! Groups Links > > > > -- ---------------------------------------------------------------------- * George Dinwiddie * http://blog.gdinwiddie.com Software Development http://www.idiacomputing.com Consultant and Coach http://www.agilemaryland.org ---------------------------------------------------------------------- ------------------------------------ Yahoo! Groups Links <*> To visit your group on the web, go to: http://groups.yahoo.com/group/testdrivendevelopment/ <*> Your email settings: Individual Email | Traditional <*> To change settings online go to: http://groups.yahoo.com/group/testdrivendevelopment/join (Yahoo! ID required) <*> To change settings via email: [email protected] [email protected] <*> To unsubscribe from this group, send an email to: [email protected] <*> Your use of Yahoo! Groups is subject to: http://docs.yahoo.com/info/terms/