00:00:17.000
I'm going to talk about um writing command line applications using test driven development so I love writing command line applications I love using
00:00:23.359
the command line I love everything about it right it's so simple and I don't have to take my hands off the keyboard and
00:00:28.560
it's just really clean and uh uh you know and I like test driven development too so uh we're going to talk about how
00:00:34.680
those things work together um a little bit of background about me just so you kind of know where I'm coming from to set this up a little um so I'm Dave
00:00:40.800
copen or Dave Tron 5000 and I am a principal engineer at a company called
00:00:46.399
op power and why the so op power is a software of services company in Washington DC and uh why that's
00:00:53.039
important is when I started I was employee number 23 probably the sixth developer that they hired so any of you
00:00:58.879
that have worked like at a startup or on a small company or something like that you know that when you have to build
00:01:05.040
your awesome product there's other things that have to happen too and you don't have a team of Specialists you
00:01:10.360
don't have a DBA and assisted man and all this stuff to help you you have to stop what you're doing and go fix it and
00:01:16.159
make things work you know automate things that are tedious or glue things together that need to be glued together and if you do it the way I used to do it
00:01:22.960
what you would do is you would hack together the crappiest bash script of all time as quickly as possible and run
00:01:28.600
it once and if it works you're good to go and you go back to what you're doing so uh that sucks right because 6 months
00:01:34.600
later it's still running and you still got to fix it and it's this horrible mess and you have no test so you have no
00:01:39.799
easy way to fix it or make it better or even figure out what it's supposed to do so when I started at op power uh you
00:01:46.240
know like I said small company at the time and I had to do these things and I decided I'm not going to do that I'm
00:01:51.640
going to write really good command line applications I'm going to take some time and take some care and and and leave
00:01:57.119
myself little bits of documentation help and all kind of things to make a nice application I loved it so much that I uh
00:02:04.159
started writing a book about it um and and I thought I had you know really thinking about all this command line
00:02:09.399
stuff I'm going to collect it all into one you know one one book and and and and get it together and I'm writing and
00:02:14.599
writing writing so here's the the proposed cover of the book um everyone in here is is is running a command line
00:02:21.239
app that's why they're so cool um I don't know if the publisher is going to go for it but
00:02:26.360
maybe so anyway as I'm writing this book I get I I realize I've got all these
00:02:32.440
great ideas but I haven't talked about testing how how the heck do I test my command line app right because
00:02:40.080
um yeah okay so so we're going to talk about why that's tricky but uh before we get into that let's do a quick review of
00:02:47.120
tddd anybody here not know what TD is I'll do it very fast just so you know
00:02:52.560
what I'm talking about so I write a test that uh that that asserts my my my app does something that it doesn't do and
00:02:59.519
then I run the test and watch it fail so I know that my test is doing something uh then I fix it as quickly simply as
00:03:05.400
possible I don't think about The Grand Design of the system I just just fix that one test get that done and then I
00:03:11.360
refactor then I clean up my little mess so I separate the the step of making work versus making nice then I repeat
00:03:18.879
this over and over and over again so um why is this hard for command line apps so we're getting back to as I started
00:03:24.920
thinking how do you you know test a command line app because what do they tend to do right they tend to copy file
00:03:30.000
to other servers or fuss with the system or delete files or mess around in my home directory so I can't be running a
00:03:35.319
test of a command line app that's going to change my system or screw up my home directory every time I run the test that's kind of a problem and uh so
00:03:42.720
that's why I sort of resisted for a while but H it's actually not that hard especially if you're using Ruby um so
00:03:48.360
what this talk is going to be about is how to deal with that and what it all comes down to is that we're writing our command line apps on production right
00:03:55.159
we're not writing them on the production server but we're writing them on the machine on which intended to be run
00:04:01.280
which means that a test that runs the command line app has a potential to screw up the very machine where it's you
00:04:07.319
know designed to run and uh avoiding this uh so so right what would you do in
00:04:13.280
a in in a regular uh web application right you would You' have a development server you'd have a QA server you'd have
00:04:18.600
a staging server and you would do all that and that's how you would keep things from from messing up um and I guess if you're whole business is
00:04:24.360
writing command line apps maybe you should do that but that's kind of crazy for writing like a backup script so um
00:04:31.960
using Ruby it's actually pretty easy to make sure that you uh don't screw things up and still can get all the benefits of
00:04:38.880
test driven development so that's what we're going to talk about um and we're going to go through uh writing a simple
00:04:44.639
application using tdd and see how this how this happens and as it turns out there's a few tools and a few ways of
00:04:51.080
thinking and a few different techniques that are probably going to seem obvious but maybe you hadn't thought of them or or maybe I'm just dumb and I hadn't
00:04:57.360
thought of them before but they should uh they should make get pretty clear how you can handle some of this stuff so our
00:05:02.639
app uh that we're going to write is going to manage our DOT files like our bash RC and and all that stuff so I
00:05:07.759
don't know about you guys but I keep mine um in a git repo you up on GitHub and so when I've got to set up a new
00:05:13.240
machine or a new account or something um I'll clone that down and then I'll Sim link all those files into my home
00:05:19.039
directory and that works okay it's kind of a pain it's a bit tedious and it's the perfect thing for a command line app
00:05:24.639
to to do for me so uh we'll we'll we'll make one right so let's let's get to it right um
00:05:32.400
so how do we start well we'll make a directory I'm going to call it full stop right that's that's British as I understand it for period um so we'll
00:05:39.280
just make a directory called Full Stop and and go right um well that sucks because now I got to piece together a bunch of rake files and Gem files and
00:05:45.240
crap like that that um maybe I don't know what to do and it's going to be like you know too long so I'll just
00:05:50.560
bundle gem full stop that's way better right because then I get a rake file and Gem spec and all that unfortunately I
00:05:55.600
can't I still can't really run tests right because what I really want is you know kind of like the Step Zero before
00:06:01.840
we do our test fix refactor thing I want to bootstrap everything when you write a rails app you type rails fo CD Fu rake
00:06:09.520
test and you get a test one test gets run that's pretty awesome right so that's what we want right because uh it
00:06:16.520
reduces the friction between us and starting to write tests and and being able to write tests as soon as we have an idea of what we want to do um without
00:06:24.440
something like this uh we rely only on our professionalism and it's kind of
00:06:29.639
hard to rely just on that if uh you're under the gun or you're under a lot of pressure so having something that enables and encourages you to start
00:06:36.280
writing tests as soon as you have an idea that's a good thing so you can um
00:06:41.440
you know make a get repo with a template project or some tarball that has what whatever you need um so I wrote a uh I wrote an app
00:06:48.520
called methadone that does all this for me according to the way I would like to uh you know write a right and test a
00:06:54.360
command line app um so when I run it it just it just basically does a bundle Gem
00:07:00.160
and then a bunch of other stuff setting up things that I need and we'll see kind of what those things are when we run a
00:07:05.280
bundle install and we have this big giant list of uh gems that get installed so what these are are not important what
00:07:11.199
what's going on here is that we're setting up cucumber um and we're setting up a thing called Aruba so Ruba is a
00:07:17.080
bunch of cucumber steps if you don't know what cucumber is we'll see it cucumber is a way to write tests in English and each each each line of your
00:07:24.759
English is a step that does your test we'll see that later anyway Aruba is a bunch of steps for test testing command
00:07:30.039
line applications so it will run your app capture the output capture the standard error let you do some asserts
00:07:36.720
um you know on like the exit status or check that the error contains something so all these handy things that we might want our app to do so so methodone is
00:07:44.120
going to set all that up for us so let's check that out here okay right so it's a basic you know
00:07:52.879
kind of standard looking stuff you might want in your project um we've got
00:07:58.440
a little app that uh does really nothing you can see there's haran code just
00:08:03.639
enough to get us going um we can run a test right so if we feel like writing
00:08:09.319
unit test we're good to go there and we can run a cucumber feature and right so that's good to go
00:08:17.199
wonderful so let's add a feature and so this is cucumber right uh feature everything from feature to scenario is
00:08:23.479
just English you can write whatever you want it's designed to get you thinking about the problem you're solving and to
00:08:28.520
write out what what's what's the reason for what you're doing but everything under scenario all this that's code that's going to execute and actually run
00:08:34.719
our test so the given and and we're writing it just in in magical English
00:08:40.039
that is what we want our app to do so given I've got my DOT files and some git repo when I run the app giving it that
00:08:47.920
that repo uh then the dot files should get checked out in in a in a directory called dot files in my home directory
00:08:53.880
and then they're going to get SIM links so that's exactly what I described before of what I wanted the app to do and this uh we we can execute all this
00:09:01.480
stuff so let's uh let's go ahead and see what happens since we've bootstrapped everything we just need to make that file see it
00:09:08.760
here right so it's the same thing without syntax highlighting so we'll run that okay well
00:09:15.560
we're looking for a failing test right we're not quite getting there so we have all this gold and all that means is the Cucumber doesn't know how to execute
00:09:21.519
those steps the one in blue cucumber does know how to execute that step and that's because this step is provided
00:09:28.360
what the h something going on there okay this step is provided by Aruba so cucumber knows
00:09:35.320
how to execute that but it can't yet because it doesn't know how to do the other ones so we're 25% of the way there
00:09:41.279
we just need to implement the rest of the steps and so here's the second part of how cucumber works so you see this all that right
00:09:48.480
there right that's the English it's matching it's just a basic reg x match and it's extracting things out of there so all we're doing in this given the
00:09:54.680
given is when we set up the conditions under which our test is going to get run so we uh kill whatever directory we've
00:10:00.680
been given uh recreate it fresh and then for all the files we're just going to make some empty files in there and then
00:10:06.399
down here we just make a little git repo right really simple but now we have a fully functional git repository and a
00:10:11.880
nice clean directory that we can rely on when we when we run our app so now to do
00:10:17.079
these assertions right to check that the dot files are there um we basically just
00:10:22.720
go into uh the directory where we expected to have cloned everything and then we call this Aruba step then a file
00:10:29.720
name whatever should exist so Ruba gives us that and a step call another step so uh it's pretty easy we don't have to
00:10:35.480
really do anything uh the second thing we need to check is that the Sim links worked so again um we're going to do the
00:10:41.760
same sort of thing right we're going to go into our home directory and for all the files that we know we're in our git repository we're going to assert that
00:10:48.639
they're a Sim link and uh so this is this is some rspec stuff here and rspc does not provide a b assim
00:10:55.680
link matcher um I provided that and we'll talk about why um but this sort of demonstrates like
00:11:01.839
why it's important to watch your tests fail so when I was developing this right I I use this code instead because this
00:11:08.120
works fine for arpec right I make a file from the file name I call elat and the
00:11:13.600
object that's returned by elat has a method called Sim link so when I say should be Sim link arpc is smart enough
00:11:19.680
to call the Sim link method and check that it returns true great so you know problem solved
00:11:26.519
unfortunately this is the message that you get right expected siming to return true got false symboling of what I have
00:11:33.000
no idea and I'm running in a loop so if this were ever to actually break I would have to go into the code and add a bunch
00:11:38.320
of puts to figure out what actually went wrong so we can write a custom matcher which is very simple uh like
00:11:46.440
this so uh we put that same test inside the match block there which RPC will call to figure out if the test failed or
00:11:52.720
not and then we get a chance to write a nice lovely message that explains what the actual problem is cool
00:11:59.920
so now okay we've done all that we're hoping to find a failing test somewhere
00:12:07.279
all right so let's see if we can do that yes okay so we see there's some
00:12:14.399
green right because we did set up our our test get repo that worked out uh when we ran the app it exited non zero
00:12:21.519
so that's green and then um we've got a big red splotch that tells us exactly
00:12:26.920
what we need to do um and so this is the actual problem that's causing the test to fail the file's not there and that's
00:12:33.760
not surprising right we haven't written any code yet so why would it be there um but we're we're pretty confident that
00:12:39.639
we're testing for that so now we're going to fix that but it's important to know we're only fixing this problem
00:12:45.600
right the way cucumber wants you to work is one step at a time so we're not going to use this test failure as some excuse
00:12:51.320
to write the entire application we're just going to fix the problem at hand take it one step at a time and see how that goes so here's the the code that
00:12:59.600
methadone gave us right it's just has option parsers set up and that's about it um so what we want to do is uh change
00:13:07.399
to our home directory and run to get clone okay so that's all we do and uh
00:13:13.720
you know rv0 that's the repository we're getting on the command line so that should hopefully uh hopefully work
00:13:21.160
there's a slight problem though right now we're getting into the weirdness of testing command line apps and home
00:13:26.920
that's my home directory so what is going to happen is this is going to get run and what God knows what that's going to do to my home directory I've got
00:13:33.040
these temp files in my home directory now what if I had my real dot files there now they're gone who knows that's
00:13:38.959
not good but I still want it to work in reality to check into my home directory
00:13:44.480
so what do we do about that well um you've noticed that I haven't used Tilda
00:13:49.760
or an explicit path anywhere in the test or in the code I've always used this home environment variable and that's I
00:13:55.160
can expect that to be set to my home directory the system guarantees it think it works on windows so um that means
00:14:03.440
that I have a way to change it so I can change that environment because when Aruba runs our app it our app will
00:14:09.959
inherit that environment so I can mess around with it and do whatever I want but still be confident that we're using
00:14:16.160
the standard home environment variable to get the home directory right because we're developing on production so uh cucumber lets us uh
00:14:23.920
write code that runs before and after every single uh scenario that we execute so what we're going to do is is create
00:14:30.440
an empty directory in temp um and set that to be our home directory by setting the home environment variable no problem
00:14:36.680
and afterwards we you know set it back just to just to be nice um so now all right crisis averted
00:14:44.720
we hope let's see how that goes right so there's no there's no dot files
00:14:50.399
directory in my home directory right now
00:14:56.160
so okay we still got some red but we got a step further right this guy right there was failing before now he's
00:15:01.519
passing our checkout is working um and still nothing was messed up in my
00:15:07.279
home directory wonderful all right so the next problem The Next Step that we need to do is fix the problem of the Sim
00:15:13.959
links not being there so here's where we left off and basically all we want to do is is all
00:15:19.399
the files in this dot files D we want to assimilate those to the current directory which is our home directory yeah and so we use uh the square bracket
00:15:27.519
thing Ur and this awful looking expression but it gives us all the files and then uh we check make sure we're not
00:15:33.040
sim linking Dot and dot dot so who knows what that's going to do and then Sim link everything
00:15:38.319
else now hopefully that will give us a nice bunch of
00:15:46.319
green all right look at that it does it all kinds of wonderful green um so right it works right so it
00:15:54.800
does exactly what we said we executed it you know we wrote down what we what we wanted it to do we executed that um but
00:16:00.800
right we're still only on step two so you should never tell anyone at this point that you're done because this the most important part is to do the
00:16:06.959
refactoring now we've only written like a few lines of code so like why refactor well why not refactor we have a test and
00:16:12.279
we can do it um so here are some things I don't like about the code that I just wrote right there's no variables so I don't know um what ARG v0 is supposed to
00:16:20.480
represent you know there's all these magic strings there's that awful reg XY thing I it's so ugly I can't stand it
00:16:25.759
even though it's useful I I want that out of there and I want to know what it means but I don't want to have to look at it I'm repeating file base name all
00:16:32.680
over the place you know that's no fun um and it's organized backwards right when I open up this file I just see a bunch
00:16:37.800
of option pars and crap I don't see the the main logic of my code which is what I want to see so let's fix that by
00:16:43.240
refactoring so we'll put a main method is the very first thing um we'll extract our magic. file string out of there um
00:16:50.160
and now since main is taking some parameters namely the repo and where we're linking to we get variable names
00:16:56.519
that explain what things are and then we replace that durt expression with a nice method called dot files in and now our
00:17:03.199
main method reads exactly like what it does dot files in then can swallow up
00:17:08.360
that awful thing which is a little bit cleaner actually now that we have uh some variables there and then we apply
00:17:14.160
some Ruby functional list comprehension magic to uh clean that up and uh we should be good to go followed by option
00:17:20.880
parsing and then we call Main so that's all good and it certainly satisfies my
00:17:26.319
need to have the code look nice but did I break anything and that is why we have a
00:17:34.679
test and no I didn't break anything meaning everything the app did before I
00:17:40.360
started messing around it still does and I can prove it beyond a shadow of a doubt that's what the test gives us and
00:17:45.760
this is going to be really handy in six months when I look at this thing after all kinds of development and it's so ugly and I have to fix it before I can
00:17:51.360
add new features got all these tests to let me do that okay so we could keep doing this
00:17:56.919
and keep adding more features um but there's a few other problems that we might want to think about that I think are going to be a little more
00:18:02.080
interesting so the UI is currently pretty terrible we're lucky to get Das D
00:18:07.240
help right because we have option parser but um you know we we document here that we take options of course we don't take
00:18:13.280
any options we document that we don't accept any command line arguments of course we require a command line argument um and there's no indication of
00:18:20.159
what this thing does you know I'm not going to remember my clever Name six months from now and this thing's pretty destructive so I would like to know what
00:18:26.000
it's supposed to do uh when I get help from it um secondly uh there's no error handling
00:18:32.240
I don't use any if statements in that whole thing and all of these system commands I mean especially with a command line app all this interaction
00:18:37.320
with the system is going to cause some problem somewhere at some time and we need to know what our app is going to do
00:18:42.400
and how it's going to handle it okay so let's deal with the sucky UI first because that's still pretty easy so here
00:18:47.720
is a feature that describes a non sucky UI you know I I get help for the app it should exit nonzero because you exit non
00:18:54.880
zero when you do what you're asked there should be a banner that bannner is that usage thing so we should have a banner should not document that it takes any
00:19:01.559
options it should document that we take an option called repo which is required and there should be a on line summary of
00:19:06.840
what the app does wonderful so fortunately for us um all these steps are provided by Aruba and methadone
00:19:13.559
already so we don't have to write them but if you don't feel like using methodone you could write them very easily like this so getting help for the
00:19:19.440
app we uh save off the app name uh use Arubas when I run and then to check the
00:19:25.559
output we then use another thing Aruba gives us the output should should match you can give it a regx and it will see
00:19:31.360
that that Reg X applies so that's why we're saving the app name right because we want the app name to show up in the
00:19:36.480
banner all right so let's see how sucky our UI is according to our new feature
00:19:42.280
file feates okay so yeah we we exited zero
00:19:49.600
that's good and and the banner was there because option pars gives it to us but then it falls down on this options thing
00:19:55.280
okay so let's fix that so rather than step through all of those painful detail we'll kind of fast forward a little bit
00:20:01.120
and we'll fix it all in you know two lines of code um so that's essentially what we want if you haven't used option parser before Banner is exactly that it
00:20:08.880
sets sets the banner
00:20:14.080
okay and now we're all green so we have a nice simple but effective and useful
00:20:21.400
help system that is not sucky anymore okay that was pretty easy and and the cool thing about this is now whenever you want to add new options you have a
00:20:28.080
way to do it via driving it with your tests and that's a good thing I don't think we need to refactor this it was
00:20:33.720
just a couple lines of code um so the unhappy path this is where it gets tricky so here's our main method again
00:20:41.760
here's all the things that could go wrong I mean the link dur might not be there git could fail uh we could you
00:20:47.880
know Sim link a file that's already there and who knows what the app is even going to do so let's find out so we'll
00:20:54.600
run it and again we're setting the home environment variable to our fake home which is still there from the last last test our fake repo still there from the
00:21:00.520
last test um so we're just this is just exploring like what would our app do so then uh we run it it runs successfully
00:21:07.000
then we remove the git repo so that what will happen the next time we run it is it will check everything out again but
00:21:12.760
then the Sim link will fail because the files are still there so we do that and sure enough that is exactly what
00:21:18.760
happens uh Ellen doesn't like that file exists horrible back Trace you know this is this is pretty pretty terrible you
00:21:26.120
know we don't we should never show back Trace right that is that is amate hour the user should never have to deal with that they should just see a message
00:21:31.440
about what went wrong so let's fix that so we write another scenario my DOT files are there and there's a file in my
00:21:38.279
home directory already then when I uh run it I should exit with nonzero
00:21:43.320
because we didn't do what we were asked to do and the standard error should include our error message and the output
00:21:48.520
should not contain a back Trace simple enough and uh here's how we set that up
00:21:53.880
so we just touch the file to you know as part of our given and then to assert we um basically just defer to uh Aruba to
00:22:00.039
say the output should not contain anle bracket main I don't know a better way to check for a back Trace in the output I mean this is kind of cheesy but it'll
00:22:06.760
work you know it'll work well enough for us all right so what
00:22:13.880
happens okay sure enough somewhere in all of this it says that the output did contain
00:22:22.000
a back Trace so it's showing us all the output that we got and then it shows us a nice little diff here um and we can
00:22:27.559
see that yeah it's it's certainly right about that all right so let's fix that here's what we're calling main we're
00:22:33.080
just going to do the simplest possible thing ever which is surrounded begin rescue which I learned yesterday is not
00:22:39.279
the greatest way to do this but whatever uh this this will this will work well
00:22:44.640
enough let's
00:22:51.760
see okay it works great that is awesome so now the user doesn't get this horrible back trace and our app is a
00:22:58.600
little bit more robust and handles errors a little bit better but that's just one case like there's all kinds of
00:23:03.840
ways that this thing could fail and they get harder and harder to simulate because how are we testing right we're setting up a a special set of files and
00:23:10.880
directories and then we're running and seeing what happens and so setting up a special bunch of files can be really
00:23:16.520
hard if we want our app to fail in certain very specific ways um you know it's lots of setup and it makes it
00:23:22.279
potentially fragile something that might happen to work on my laptop might happen to not work on your laptop so what we
00:23:27.760
need to do is use tests unit test will allow us to um really isolate exact behaviors that we want to test for and
00:23:34.000
see how that goes um they also run fast right we don't have to set up anything we don't have to actually run the app
00:23:40.600
and you know testable units are good right we want units in our code we want little bits of code that do small simple
00:23:46.039
things so having a unit test means we have to have units and uh that'll be a good thing so since all of our tests are
00:23:53.240
passing we can refactor we can refactor anytime the tests are passing so let's do that to give ourselves the ability to test what we've done with the unit test
00:24:01.080
here is the code again um magically formatted so that when we extract it from the executable and we wrap it in a
00:24:07.400
class and put it in our lib directory uh we can now use this without having to run the application meaning we can test
00:24:13.960
it I'm also going to change that percent X to call system these will have a
00:24:19.039
similar effect except that system has the uh ability of me being able to mock it whereas I don't know how to mock
00:24:24.720
percent X um so right and then our utable uh all we need to do is just you
00:24:30.840
know call it from the CLI class instead of instead of be and everything's good we hope so before we do anything we got
00:24:38.000
to make sure we didn't screw anything up and we did not everything's still
00:24:43.640
good the refactor was good the app still works as expected okay so what's our approach
00:24:50.480
going to be um so we're going to test the main method and we're going to say that there's any problem anywhere in that method we're just going to raise an exception because the uh the executable
00:24:59.159
already handles getting an exception and printing that message to the user and exiting nonzero so we've already got
00:25:04.480
that taken care of so we can just let main throw an exception so we'll need a new test um now the file utils methods
00:25:11.159
they do throw exceptions already so let's not test them first I mean we might want to eventually but now they we
00:25:16.520
know that that's going to kind of get handled okay system on the other hand doesn't it returns true or false
00:25:21.720
depending on if the application that it calls exited zero or non zero so what we'll do is we'll mock system to return
00:25:28.320
turn false every time see how that goes okay so here we're going to set it up and I'm using test unit because I like
00:25:33.840
test unit you know if you don't too bad um we're going to stub CLI to just do
00:25:39.600
nothing unchanged dur for system it's going to return false and then for Ln it's going to raise an exception because
00:25:44.919
we shouldn't get that far the expected behavior is that when system returns false we raise an exception that there
00:25:49.960
is a problem and we do not proceed with the Ln and then to test that we'll assert that calling main raises a
00:25:56.480
runtime error and we also Al assert that the message of that runtime error is something that explains the actual
00:26:02.640
problem so we want to be clear about where in the code the exception came from and exactly what went wrong so we
00:26:10.240
got that see how that goes so now we're in test land so we
00:26:15.799
test okay unfortunately it's not in red I'm sorry I wish it were but we see here runtime error expected but nothing was
00:26:22.120
raised all right that's uh that's not surprising so we'll fix that so here is
00:26:28.520
the here's the call that we have now um and essentially what we're going to do is say unless system so we're going to actually check the return code then we
00:26:34.600
raise an error and we include the command in the string again we're fixing this the simplest quickest possible
00:26:45.080
way and sure enough it works and just to make sure we didn't mess anything else up everything else that the app does it
00:26:52.760
still does great so refactor right this is awful um
00:26:58.399
there's first of all there's control statement in there which I don't want to see second I'm repeating the command twice so that's no good um so let's yank
00:27:05.919
that out into a method called uh sh bang because it phrases an exception so we'll put a bang in there and doing that
00:27:12.559
requires uh you know gets us this thing in a command so we're not repeating the command twice and now our codee's still nice and kind of readable still looks
00:27:18.799
like a little you know shell scripty thing there so that's uh I like that so
00:27:24.760
now test okay that looks
00:27:30.440
good features okay that looks good so now we
00:27:36.039
have handle that great so you know we could continue doing that and and handle all the different cases and the cool
00:27:41.519
thing about unit test and about using mocking is that you can set up the exact conditions of failure that you want to
00:27:47.320
simulate um so I'm way ahead of time that's okay um so this is you know
00:27:52.960
mostly what I wanted to share with you hopefully this this got your kind of juices flowing I mean none of this is too terribly compc but bring it all
00:27:59.519
together it took me took me a little bit to figure out how to do it so basically what you should take away is starting with a template right rails is nice
00:28:06.320
because you get a template so you should have that for your command line apps too and if you you think you're going to be writing more than one of them set up a
00:28:11.559
template project for yourself use methodone use your own thing doesn't matter um start from the outside in so I
00:28:17.240
think it's handy to start with cucumber and start testing the user interface because that's how the user you are
00:28:22.600
going to be interacting with this thing so it makes it very easy to think about how it's supposed to work and what effect it's going to have of course as
00:28:28.320
soon as things start getting complicated right you want to get to your unit tests so that you can simulate all the little
00:28:33.640
esoteric side cases and weird things that could happen um and finally designing for testability is okay right
00:28:39.720
I replace that percent x with system specifically for testing and it's okay to design your app to make it easy to
00:28:45.799
test because then your app is easy to test um so that's all I had to share with you for today I appreciate it and
00:28:52.120
we ended it early so I have you know some time for questions if anybody has any
00:28:59.559
hey oh Jesus uh I had to I had to rewrite it so uh I'm almost done they're
00:29:04.880
supposed to announce it um uh next month oh
00:29:12.039
hey what's that yeah you know I just discovered it the other day one thing in this looking
00:29:18.320
at command line stuff the searchability of these tools are terrible and so there's like 10 things that do the same stuff so I had written this whole
00:29:24.039
methodone thing and it's pretty basic and then I saw the main jam and I'm like oh that's that's kind of like what I what I was doing so I don't know how
00:29:30.760
much I'll continue down it um yeah but s just searching for that outside of GitHub is very difficult because main is
00:29:57.039
everywhere so are are you wondering about um
00:30:02.279
leaving droppings around after the
00:30:09.159
tests oh yeah yeah yeah so um if you if you package it all up with ruby gems it actually pretty much takes care of it
00:30:15.760
and so if your sisadmin are cool with using ruby gems that makes it you know easy if they're not um you can turn a
00:30:21.200
gem into like an RPM and you can install it that way uh you know it works um but
00:30:27.120
I guess if you're really TR you can just jam it all into one file if you really wanted
00:30:44.720
to
00:30:50.360
yeah um I have not and I I dug a little bit into the Aruba internals like you
00:30:55.519
know researching this and and figuring this out and it's still very early um there's there's some wackiness in there
00:31:01.440
like it saves the output of every app it's ever run in the test and things like that so I'm not really not really
00:31:07.480
sure but that's that's an interesting thought to just stub out system and try to do stuff that way make everything run
00:31:12.519
faster I
00:31:18.960
guess all right well uh thank you guys and uh enjoy the early