Pages

Wednesday, October 05, 2016

RubyConf 2015 - A Guided Read of Minitest by Nate Berkopec

ese.Oh boy.Alright, so, my name is Nate,I'm gonna talk into the mic while I do this, here.And today we're gonna talk about Minitest.I know in the program it saida guided read, and we are gonna read code today.This is basically a code reading talk.But, as I was writing this talkI realized it's really about pain.The pain that testing makes us feel.So we're gonna talk about pain.You probably could have titled this talk something else.Minitest: It Hurt Me And I Liked It.(laughter)My name's Name's Nate Berkopec.I write about full-stack Ruby app performanceat Nateberkopec.com.Performance is my usual wheelhouse.I'm not a testing guy,I don't usually write about testing.Testing is sort of, the last thingon my code skill improvement list sometimes.But, Minitest played a huge partin my evolution as a tester,and, as I'm going to show you, as a Rubyist.So that's why I wanted to comeand talk about it here to you today.Oop, wrong way.I'm gonna start off by telling you a story.I started learning to programin 2010.I was a college senior.Ruby was my first programming language.I wanted to get a job at a big flashy startup,and I thought the best way to do thatwould be to become a programmer.Turned out that was true.When I started learning RubyI used Michael Hartl's Rails tutorial,I had no computer science background.And if you've ever looked at that,you know Michael Hartl does a great jobof teaching you TDD from the start.But, he uses R-spec,and for a long time when I startedwith Ruby, testing was really hard for me.I was just getting started with Ruby,I barely understood what I was doingwith Ruby to begin with,and then along comes R-specand there's sort of like, well you gotta learn"describe" and "it" andall these other words that R-specconcepts that R-spec brings to you,and says, you have to learn those, too.And for a while that was really frustrating to me.And then I found Minitest.And it was kind of like a brand new day for me.It was like, oh, it's just Ruby,I can just write whatever I want,you might have heard this sort of line beforeif you've ever done anything with Minitest.I knew the API was very simpleand it was a lot easier for meas a beginning Rubyist to write.But...I came upon this testand I wanted to stub an object,I wanted to stub an object's instance method.And I was really frustrated,'cause it seemed like there was no wayin Minitest to do that.And I went into the Minitest IRC channel,and I said, "Guys, this is dumb."R-spec makes it really easy to do this,"and why won't you let me stub an instance method?"And Mike Moore,the maintainer of the Minitest Rails Gem,among other things,oops, I keep going the wrong direction, here,said, "Well, that's 'cause we already"have it in Ruby."It's called a singleton method."I was like what?You can do that?And that sort of startedthis long love affair with Minitestwhere Minitest kept showing me partsof Ruby that I'd never looked at,or I'd never understood.And so, by reading Minitest source code,we can re-engage with Ruby.In this way, pain,feeling this pain of,ugh it's really hard to do X-Y-Z,led me to learn something new about Ruby.Is this a talk about Minitest,it's in the Less Code track,so I do have to address the elephant in the room,and that is RSpec.I think the originalCFP, or something, for this conference,this track specifically, said that Less Codewas like 500 lines or less.Minitest is not that small,but I did get into Less Code track anyway,and I think it's 'cause we all understandthat Minitest is small in comparisonto the other options that we usuallyreach for when testingin Ruby.But I'm not here to play internet fight,I'm not here to talk about RSpec,I'm here to talk about Minitest.And to get it totally out there,I mean, it's pretty obvious,I came to give a talk about Minitest,I am a Minitest guy,so I want you to take everything I'm sayinghere with that grain of salt in mind,I don't want you to swallow everythingI'm saying herejust wholesale.This talk is about the philosophy of Minitestrevealed through its code,and we can't really talk about thatwithout talking about RSpec,because a lot of what makes Minitest'sphilosophy so interestingis what it doesn't do.And we can't talk about what something doesn't dowithout talking about something that does it.And in that way I think Minitest is best thought ofas a reactionary testing framework.It's a reaction to other kinds, or other stylesof testing.Bit of a history lesson here,the original Minitestwas 90 lines of code.Ryan Davis, sitting right up here in frontwas nice enough to resurrect that version for me,and it's available thereat "tinyurl.com/originalminitest,"for an interesting read.And if you've ever wanted to knowwhat being terrified feels like, it's talking aboutsomeone's library while they're sitting in the front row.(laughs) And Ryan has said in otherconference talks thatit was originally a replacement for test-unit.He sat down,was saddled with the maintainershipof test-unit, thought it wastoo complicated to even understand,and wanted to see if he could write somethingthat did what test-unit does,but in less code.And it's from that beginning that we haveMinitest, that we have today.Before we actually read a single line of code though,I think you can learn a lot from a project'sfile structure, and its general,where its lines of codes live,and how many there are.So before I dig into a library,I think one of the greatest things you can dois open up Cloc.It's this little library forcounting the lines of code in a project,it's smart enough to break things outby file, to break things out by language,so if you have multiple languages in a project,it'll say, oh, well it's got ten thousand linesof Ruby and five thousand lines of Javascriptand so on and so on.And if we apply Cloc to Minitest, you get thiscrazy output, but the gist of it is,Minitest has 1,699 lines of documentationin the form of its readme,and all the non-blank comment lines.And just 1,586 lines of Ruby code.That's also blanks removed.That maybe sounds like a lot, I guess,a thousand is like, a big number.But, let's take a look at something else,so RSpec has four major components.Minitest lives in one Gem.There's a huge plugin infrastructure,but if you Gem Minitest, there's noMinitest dash a million other thingsthat get required.RSpec has four major componentsthat get required when you add RSpecto your Gem file, that is rspec-core,expectations, mocks,and all three of those dependon something called rspec-support.In total that is one thousand, five hundred,eight hundred and, well 43 lines,I just messed up saying that.But it's a lot!It's a big number, it's so big I can't even say it.(crowd laughing)Minitest's entire library is about as bigas RSpec's support library.So Minitest is about one tenth the sizeof RSpec in total.If Minitest was The Mouse and The Motorcycleby Beverly Cleary, RSpec is Ulysses,by James Joyce.That is a literal relative size comparison.I'm not sure how farthat metaphor goes, but Ulysses involvessome guy getting plastered, wandering around,and not much happens,which sort of describes my experiencereading RSpec in preparation for this talk.So, that's Minitest's philosophy point number one,do less with less.You don't go from 15,000 lines of codeto 1,500 just by cutting outlike waste, and being a better Rubyistthan everyone else.You get it by cutting scope.And, so when we go in and start reading Minitest,we're gonna be looking for the thingsthat Minitest doesn't do.Another good example, RSpec includes1,639 lines of formatters,just for printing your test results.There is an HTML formatter, JSON formatter,a whole bunch of other ones that I don'tknow what they do.But, Minitest spendsit's entire library doing what RSpec doesjust to show you what it did.So, moving on from that, I guess,rspec-mocks, and this is a particular example,I think, of a difference in priority,between RSpec and Minitest,is 28 times larger than Minitest'sincluded mocking library.You can use any mocking library you wantwith Minitest,but the one that's included is thisminitest-mock.rb file.And that is 28 times smallerthan what RSpec includes by default.So, without even reading mock.rb,or reading rspec-mocks,I think it's fair to say that Minitest is a Statisttesting library. (crowd laughing)That Minitest is, not in like the Stalin way,but in the Statist mockist...testing philosophy dichotomy.If you don't know what I mean by that,I think the late James Golick said it best."A stateist tester asserts that a method"returns a particular value."A mockist tester asserts that a method triggers"a specific set of interactions"with the object's dependencies."And, this is not, oop, wrong button.So, we knowthat if Minitest is gonna provide us 28 timesless mocking power and capacity than RSpec is,mocking in Minitest will be hard.We will experience pain with Minitest,like I did, when usingtest doubles, mocks, stubs.And I think Minitest is trying to tell us somethingwith that, it's trying to say, don't do that.If this is hard, maybe you should try something else.Maybe you should trycode that doesn't need this, so,that doesn't need mocking.So, that was kind of the first instanceof, I think Minitest using pain to put us downa particular testing and coding path.And here's another.The largest file in RSpec coreis configuration.rb.It is 758 lines, again, roughly half the sizeof Minitest in total.The largest file in Minitest is minitest.rb.446 lines.And what I think Minitest is kinda saying hereis that configuration,maybe this is like sort of the old Rails sayingthat we've always heard, like,convention over configuration.I've been trying to run with this pain theme, here,so I think it's, Minitest knows what's best for you,and you better do it, dammit.Configuration is not a huge componentin Minitest when we compare to reading RSpec.Minitest is extensible,and we're gonna see that in some of the codethat we read here in a second.But we should not expecta huge amount of configurationor that sort of like...settings and that sort of business.Ryan has called this,"turning testing up to 11."I would say it means that Minitesthas a testing philosophy and it wouldlike you to adopt that when using it.It's designed to teach you a certain style,and that style is not necessarilyup for debate when using Minitest.It's extendable, but it's not really configurable.And I would contrast that with RSpec'sapproach, which seems to suggestthat anything is possible with RSpec.There's all these hooks,there's all these configuration points,ways to make RSpec do whatever you want.And you can do that with Minitest,but maybe it'll be a little more painfulthan RSpec.And maybe you should think twice before doing that.So, you might be thinking, Nate,you've talked for about fifteen minutes now,and we haven't looked at a single line of codeand I agree.So, let's talk about Minitest.How does it work?Here's a typicalextremely simpleMinitest test.I want to call your attention tothe conceptsor big things that Minitestis going to require you to understandto use Minitest.We require something, okay,cool, like I'm a Rubyist, I knowwhat requiring does.Or maybe I have some idea.There's a class, alright?I've used those before, I've seenthat once or twice.It inherits from something called Minitest-test.So that's interesting, we need to understandwhat Minitest-test isand what it's gonna give us.'Cause as soon as we inherit froma class, right, we're gonna get all that class's methods,so Minitest-test could have a million methodsand then now we're working in that world, so,who knows what's happening there.And then, we have def,we have a method, which is test-the-truth.I could pick a bigger example here,but, if you had a larger Minitest-testyou would notice that every method,or most of the methods startedwith test underscore something.So that's interesting, probly has a meaningthat we should look for in the code.And finally we've got this method,which probably, 'cause we can guess,there's an inheritance here.Assert-equal probably comes from Minitest-test,which takes two parameters.So, those are the conceptsthat we're gonna be looking for digging into the code.If we run that file, just with Ruby,the command line tool,we get all this output.We don't know how that output shows up.So, let's start from the beginning.Requiring Minitest slash autorun.My guess would be that I shouldgo looking in Minitest's libraryfor an autorun.rb file in lib,Minitest, autorun,which is exactly what I find.Slightly simplified, I cut some stuffout of the beginning here,but this is what that file looks like,it just requires some other files,which is great, we know how that works,and calls Minitest.autorun.Well, where's Minitest.autorun live?It lives in Minitest.rb,which was what we might expectif we were looking for a class methodon Minitest.And it looks like this.Now, you might be thinking, Nate,I thought you were trying to sell meon Minitest was the simple testing libraryand look at how complicated that method is!And I think that's interesting.I had that same initial reaction looking at this code,and I want you to pay--- [Voiceover] So do I. - (laughs) So does Ryan.But, I want you to pay attention tothe shape of this method,like if you stood here, and squinted,and just paid attention to,alright it's about ten lines,it's fairly sequential, there's not,there's one sort of long line here,but otherwise it's pretty short.And there's just one method here, right?I think...yeah, there's only one other Minitest methodthat's called here.Minitesta.run,we've got some Ruby stuff here, like at-exit,we're setting some variables and stuff,but there's only Minitest.run.That pattern is gonna have to happen a lot moreas we keep reading this library.And I think that that patternis in great contrast to RSpec, which I'm goingto get to in a second.All Minitest is doing here is installingan at-exit hook.If you were wondering, from the previous example,how does Minitest know to run our tests?It's required before we define any of our tests,so how does Minitest knowwhere our tests are, and how to run them?That's because when your program runs,there's nothing to do,'cause there's no code to execute,there's no Minitest.run at the bottomof your test file.So, your program just exits.And when it exits,basically we do some other stuff,and then call Minitest.run.Nine tenths of this methodis defining some stuff togive you the proper Unix exit code,but really the meat of it here, is Minitest.run.If we just sort of collapsedthe at-exit block here,it would just say at-exit,do some stuff, unless,class variable, installed-at-exit,then set it to true.Clearly it just meant to prevent usfrom running that method twice.Fine, not complicated.This is how RSpec does that.Not that much more code,maybe like twice as much code.Literally just does the same thing,installs an at-exit hook.But, again, I want you to pay attentionto the shape.Very different, very interesting.One, two, three, four, five,and I eliminated like five other methods,that RSpec defines tocarry out this whole at-exit process.This is interesting, you probly can't read thisdown here, but the disable-autorunclass method on RSpecjust sets the autorun-disabled instance variableto true.That's an interesting patternthat you don't see anywhere in Minitest.I think it's a very interestingexpression of, this is what RSpec considersreadable, versus what Minitest considers readable.Minitest says, you're a Rubyist,you know what this means, it meansthat we've installed something at exit.And RSpec says, well, we need to ask,we need to put that behindthis accessor that we've written here.Very interesting, you're going to see that a lot.And it's (laughs) also kind of funny,RSpec does all this to install this at-exit hookand then tells you not to use it,because they want you to use the RSpec test runner,when you type RSpec, whatever-file.rb.There is no test runner included in Minitest.You just use the Ruby command line interface,although there are plenty of Minitest compatibletest runners, like the one you use in Rails.Oh, that's the better view of that exampleI just gave you, there.Again, very interesting differences,in opinion on what is readableand what is not.So I think that this means that Minitestis trying to tell you thatMinitest thinks that you should dothe simplest thing that could possibly work.And I want you to note the differing philosophies, here,on simple.RSpec, in terms of its testing interface as well,tends to think that simple is English readable,or looks vaguely like English.And that's sort of the whole spec syntaxmindset.But I think in a lot of ways, Minitest says,well you're a Rubyist, Ruby's simple,just read Ruby.At the end of thatat-exit hook that we installed earlier,you'll remember we called Minitest.run,and that's what determines the exit code.Let's look at Minitest.run.Alright, so right off the bat, before we even get to,again, look at the method shape here, very differentthan a lot of what you find in RSpec.And I'm kind of picking out some of the mostcomplicated stuff in Minitest, like,this whole stack of,Minitest goes through this whole stack of methodsbefore it actually runs your test,and it's kind of the more complicatedstuff in Minitest.There's a lot that's a lot simpler than this.But right off the bat, before we even getto the second line, here, check this out.Self.run, reporter options,where the hell are the parentheses here, Ryan?Where'd those go?(crowd calling out)So let's talk about Seattle style for a little bit.For the uninitiated,Seattle style, I think has a lot of differentdefinitions, for the purposes of this talk,I'm just going to say, it's sometimes interpretedas don't use parentheses in method definitions.Sometimes you go further and say don't useparentheses except where absolutely necessary.Which kind of leads to some interesting style choices,it's not super popular.David Brady gave this great exampleof parentheses usage.I'm gonna preface this by sayingthis sort of code that you're looking at right nowdoes not exist in Minitest, this does not,something similar that you would seein Minitest, I'm just making this up.We've got hash.fetch,delete, and then puts, right?I agree thatparentheses makes this more readable, right?Parentheses are sort of like this tunnel vision,you can say alright, what's the inner mostparentheses here, okay,the foo symbol, alright,let's go out one level, okay,hash.fetch, okay so we're gonnafetch the foo symbol from this hash,alright, outside of the next set of parentheses.Alright, array.delete,okay we're gonna delete that thing from an array,got it, and then we're gonna put it to the screen,okay, fine.But, maybe that's not the dichotomy here,maybe that's not thereason that we're not using parentheses.What if that code looked like this?This is a contrived example, so I don't thinkit plays as well, but I couldn't thinkof a good, actual code example for this.What if we blew the original code out into three linesinstead, did something like,actually described what the thing wasthat we were getting out of this hash,and then putting the side effect onto a different line.Just an idea, I think this is a lot more readable.I think it might be interesting.I've honestly never considered this untilI read the Minitest source code all the way through.It might be interesting totake parentheses out of your code,when you're writing it, and then seewhat that makes you do.What does your Ruby code have to look likewhen not using parentheses in order to be readable?Is that result more readablethan using parentheses at all?An interesting exercise, I think,I'm know I'm gonna be doing thatin the future, just to see if I like it.So what I'm trying to say with all this is thatI think Minitest has a philosophythat pain is good.And we can navigateour coding with pain.We can use it as a kind of signal,as a kind of,well I feel pain here, so what does that mean,what should I do?Is there a way I can make this go awaywithout just hiding it?I already talked about the mocks example,I think what Minitest is saying thereis mocks are painful here,try writing code that doesn't need the mocks,rather than coming up with a better mocking library,or a mocking library that makes this code easier.Minitest also makes adding assertions very easy,which I'm gonna talk about in a second.When it's doing this I think it's saying,it's trying to give you the opposite,it's saying, well,making new assertions are easy in Minitest,so I am encouraging you to write your own assertions.RSpec makes it easy,but it makes it difficult to understand.Seattle style can encouragethe use of local variables' intention-revealingmethod names,and, perhaps, I think, the Seattle styletries to suggest to us, parentheses are sometimesa band-aid on a problemthat we should fix without them.So, I've kind of outlined how Minitest startsrunning your tests,but how does it actually know where your tests are,how does it know how to run them?Minitest has this class runnable,which Minitest-test inherits from this runnable.And basically I've omitted a ton of codefrom runnable here, but,all it does is keeps track of this class variable,runnables, simple enough.And then you see this method, class methodinherited, which just adds something to the runnablesarray, and then calls super.I'd never seen this before,so I had to go look it up.I first searched through the projectand said well, where is inherited defined?It's not in the project.Okay, well it must be something in Ruby.Inherited is a callback that you get for free,I think it's on class, it might be on module.And it's just called any time thatyou get a new sub-class defined.This is just straight from the Ruby documentation,as an example,if we sub-class foo,this method will get called withthe new sub-classas an argument.So literally all that's gonna happen here,is my testwill get passed as an argumentto Minitest runnable inherited,which will add it to the runnables array.Eventually, Minitest looks atthe Minitest runnables arrayfor all of the test classes that it knows aboutand just runs through them one after another.I'm not gonna talk about test discoveryin RSpec, I ran out of time.Standard Lib is used very heavilyin the Minitest source code.We see things like OptionParser, Thread,Mutex, StringIO, Tempfile.And in something I can't say I'veever really seen before,Minitest will use your system Diff toolwhen printingthe difference between two large objects,like if you assert-equal, some huge array,some other huge array, and like one thingin that huge array is different,Minitest will use Diffto figure out which thing was different.RSpec implements their own version.RSpec implements that in Ruby.And Minitest instead says,well I'm just gonna use what's provided.Interestingly, a lot of RSpecre-implements a lot of Core and Standard Lib classes.They have their own version of Set,they have their own version of Flat Map.They use their own version of Thread Local Variables,and they even have their own Rand implementation.Some of these I understand,these two I think have Ruby version issues,not sure about Thread Local Variables,but threading's a total, you know,put your hands up thing in Ruby, so,maybe there's a good reason for that.Rand, I don't know.I was looking at,I don't think I put the example in here,but...RSpec uses its own algorithm forsetting the random seed in your test sweep.There was some code comment that thisimplementation that they use is just like,somehow better,that's it, it's better somehow.I don't know.So I think Minitest has a philosophyto use what is given to you.To use what is given to you by the system,to use what is given to you by Ruby itself.That's an interesting philosophy that I think issomething that we're really not used to,as Ruby developers, and I thinkit's to our detriment.A lot of us have a kitchen-sink philosophywhen it comes to our Gem files.If there's some library that will saveme ten minutes of effort,that I can put on my Gem file, then I will do it.Devise I think is kind of the worstoffender here, not because Devise is a bad library,but because we use Devise to do simple,user passname authentication that we couldjust write ourselves or use Rails facilitiesfor that, and be done in ten lines of code.Anyway, so I think that's an interesting philosophypoint from, that we can take out of reading Minitest.So how do we actually define...am I saying test, here?Yeah, so how do we define a test?How do we define the...if we say a class file is sort ofa collection of many differentthings we want to test in Minitest,how do we define one of those?This is in, where is this,Minitest-test.rb, and it gets calledin Minitest.run, which was ona previous slide.We ask a Minitest-test sub-classfor its runnable methods,we say, dear sub-class,please tell me which methods you wouldlike me to run.On Minitest-test that...is really, this is all just ordering them.It's just this methods matching some regex,which is just matching test underscore.The methods matching method is literallyjust a one line error that basically justcalls Grep on the collection of methodsand brings them back as an array of strings.So really it's just, okay, a test in Minitestis just a method that starts with test underscore.Also interesting I think that thisis not configurable.There's no, you can monkey patch it of course,but it's not like some, there's not some hookprovided that let's you change outthat regular expression.Very different in RSpec.RSpec has, from what I can tell,13 different ways to define a test,or an example.Granted, they do a little different thingsin RSpec, but there are three that do exactlythe same thing.Example in specify,there's ways to define a test while alsofocusing and skipping at the same time.And there's also a pending example,pending apparently has some other semanticmeaning in RSpec.And this method here is also provided for you in RSpec,so you can do this yourself, you can say, well,I want the smiley face emojito define a test method in my RSpec tests,so I can do that.Minitest says, that doesn't matter, just do it this way,it's fine.There's maybe some reasons for this,but if you don't think thatExit being a way to skip a test because of,I don't know, I thinkJ-unit or X-unit used to do that.If that doesn't matter to you,then maybe RSpec is providingother things that don't matter to you.This is RSpec implementation of defineexample method.Does this thing called item potently definesingleton method.I'm not a computer scientist, so,like I don't really know what this word means.I know what a singleton method is,but I don't know why they didn't just do that,instead of calling this other method that I guessdoes it for me.There's some metadata,I don't know what metadata is.And, well this I understand, examples.Yup, there's some examples here,we're adding an example there,that's cool.Very different approach.So, what I think Minitestis espousing here, is to reduce our API services,let the user define their own aliases if they want,and make it simple to do so.And I think that kind of goes along withlimiting configurability.I'm kind of running out of time, here,I'm okay.Yeah, just talk faster, Nate.Let's talk about assertions really quick.This is an example of assertion in Minitest.The structure, as you can see,is really simple.If you look at Minitest-assertions.rb,they literally all look like this,they're all like three lines.It defines a message that we print ifthe assertion fails, and then makes an assertionusing the assert method.So, Minitest doesn't really provideany facility for writing your ownassertions, it just says do thison your own tests.Just open up Minitest-test or open upyour test class, and write somethingthat looks like this.There's no specific facility,like what RSpec provides,to define a newassertion or matcher, as RSpec calls them.This is what assert looks like.Not any more complicated.We increment our assertions count by one,and then run the test,the thing that we wanna test,and if that returns true,we just keep moving, and if it doesn't return true,we're going to raise this special kind of exception,which Minitest handles in its own way,I don't have time to get into that, unfortunately.And you might have noticed here thatmessage is a proc, which is sort of interesting.Maybe a little more complicated.Originally it was just a string,but if you think about it,if we're calculating the error messageevery time we run the test, eventuallythat's gonna get very expensive.So by putting it into a proc,we can only calculate an error messagewhen we actually need it.You don't have to do thatwhen writing your own assertions,because if it's just a string or whatever,Minitest will just print it.If you don't care about that orif it's not a big problem for you.And the way that these get includedinto your test, these assertions,is we just include the assertions modulein Minitest-test.We've all done that a hundred times,no big deal.RSpec, I honestly have no ideahow they do this.The expectations Gem itselfis like 3,000 lines, and then there'sshoulda-matchers which is another 6,000 lines.I really honestly, I've sat down and read RSpecto try to give it an honest comparison in this talk.This part of RSpec I could not understand.This is the facility that RSpec providesfor defining your own matchers.It's interesting 'cause this is verycharacteristic of RSpec.It reads quite well,if you like read it out loud in English.But, these are all new concepts,which you have to go learn aboutand understand how they work.This define method.Where this match method comes from,I have no idea.And what these block arguments are actuallydoing, I think are all questions that you have to goask RSpec about.Whereasthis, use a module,and call this method that raises a Minitest-assertion,that's pretty simple to me, I guess.What I think Minitest is saying is that abstractionis the enemy.The pain here is that you will have towrite your own abstractions sometimes.I think that's okay, I think that makes usbetter Rubyists and I thinklearning to write abstractions wellis one of the greatest skillsthat we can learn as programmers.And God forbid that you learn someRuby along the way,rather than learning how to better useRSpec.To extend and use Minitestin a greater capacity, you usuallyjust have to write more Ruby.With RSpec you have to learn to use RSpec better.Because it's a DSL that you have to interact with.So I think, I hope this has shown, through a little bitof code, though not as much as I would like,that Minitest in a lot of ways is a philosophy about pain.At least, it is to me.And maybe you've had pain with many tests in the past,maybe if you think back,and on a time that you've had to struggle with Minitest,or any time that you've struggled with Ruby, really,did you just give up, and go throw Devise in your Gem file?Or go throwwhatever Gem you thought you neededto get this done without you having, God forbid,having to write any more code.Or did you listen to that pain?And did you think about what that painwas trying to tell you?I think in programming,like life, what doesn't kill usmakes us just that little bit stronger.Thank you, that has been my talk.(applause)Please go read Minitest, if you haven't,it's really easy to read.And...go test, more. (laughs)And my slides are available at that URL.I guess, I have five minutes, so if anyonehas any questions?No? Cool.Thank you for listening to me yapfor 45 minutes, appreciate it.