00:00:16.800
welcome to rails comum I am Brian Soden uh rails Ruby Java consultant I run a
00:00:24.880
small company in Scottdale Arizona and I'm here to talk about arpec and cap bar and testing is one of those
00:00:32.920
uh subjects that in most Frameworks and languages we kind of took for granted
00:00:38.239
it's like oh it's the stuff that we do at the end of the show so the rails Community actually took that and flipped
00:00:44.600
it on his head uh I believe probably one of the earliest versions of rails already had a built-in testing framework
00:00:51.719
that showed that you could automate web testing so in this talk I'm going to talk about practical behavior-driven
00:00:58.480
development we're going to be talking about test driven development tdd and uh I'm going to try not to be
00:01:03.879
dogmatic about it and one of the things that kind of um drove me away from testing early on was that people were
00:01:10.360
too religious about it it just it felt really weird like I'm I was joining a cult but once I actually got into the
00:01:16.200
practice of it I started seeing the value so I'm going to show you some of the practices that I use in my daily work and how tdd andr spect in capy bar
00:01:24.920
can help you build better applications uh I want to be able to uh make make you comfortable with the tools
00:01:31.159
rspec and copy bar and the specific talk and the
00:01:36.680
practices so for today you're going to need git I do have a backup sit fi zp
00:01:42.439
file so if you don't have git we can probably try that uh I will have to break to show you the link for that it's
00:01:48.960
actually the same link as the PDF but with zip at the end so a very nice
00:01:54.159
lengthy URL for you to type uh rvm I do have an RV
00:02:01.000
rvmc uh rvmrc file in the application that you're going to be playing with uh
00:02:07.280
that would just create a gem set for you to work with so let me see a show of hands how many of you uh are familiar
00:02:12.560
with G oh cake this is awesome how about
00:02:18.280
rvm all right Ruby all right so if you got all that
00:02:24.920
stuff we're good to go we're we're going to be cooking with fire and I don't really care about what text editor you
00:02:30.120
use uh as long as you have a a curity uh keyboard we should probably be good to
00:02:35.920
go so it's uh we have 80 minutes of time to cover arpec and capy Bara I'm going
00:02:41.400
to start with arpec uh bdd and TD then we'll jump into capibara 40 minutes and
00:02:46.680
40 minutes I'm going to mix lecture and code and follow along coding so it's not
00:02:52.480
one of those that you can basically listen to the lecture and skip out of town so hopefully you're ready to actually write some code not too much
00:02:59.680
but but enough I have two um images on the slides that indicate
00:03:05.480
whether I want you to follow along with me uh which is that green follow along sign and there's two Labs two very
00:03:12.080
simple Labs that we're going to uh be able to do at the end of each of the 40 minute
00:03:17.680
sessions all right so let's talk about testing unit integration acceptance
00:03:23.799
behavior-driven development in test driven development it's a lot of acronyms to be thrown out there
00:03:30.840
in the agile Manifesto this is the the actual phrase that that stood up uh in
00:03:36.560
my mind when I was actually trying to correlate testing with the quality of our applications and it's that the your
00:03:42.680
our highest priority is to deliver the most value to the customer and value doesn't mean documentation doesn't mean
00:03:49.959
anything other than code runable testable reproducible behavior and code
00:03:55.760
it's what our customers are looking for and that is the direction that the practices in the rails and rubby
00:04:01.519
Community have taken uh development towards so let me see how many of you
00:04:08.319
came from let's say a Java background okay get out know just get in
00:04:14.760
just get I'm there too how about C C++ all right when I was doing C and C++
00:04:22.280
I mean testing was the last thing in our minds we actually ran through the whole code testing was basically visual you
00:04:28.960
know uh or we actually would look at the behavior of the application and hope for the best and if somebody changed
00:04:34.280
something as the application got more and more complex things got more and more complex to verify so testing you
00:04:40.440
know in the waterfall methodology was the thing that we did at the end obviously most projects had a flag in the sand in terms of a calendar date
00:04:47.320
that they wanted to be done by and we never actually got to slap the testing into that period of time we ended up
00:04:53.919
basically saying oh well you know it didn't quite happen most languages didn't have a good
00:05:00.199
framework support for testing and uh it all started with small talk but really with Java and junit and from that point
00:05:07.360
on things really Sprout you know testing Frameworks appear in every language that we see out
00:05:13.400
there in the Ruby world we had test unit from the get-go um I'm going to be
00:05:18.919
showing aspect which is now I would say an evolution on test unit it's test unit
00:05:25.120
with the language uh capabilities to do behavior-driven development
00:05:31.800
one of the problems with unit testing Frameworks is that when we start using them we learn to unit test but the unit
00:05:37.960
testing Frameworks are used to do every uh aspect of testing from integration to uh acceptance user
00:05:46.319
testing everything is done with the same framework so our problem is where to start and we always start at the unit
00:05:51.880
because that's what we learn the framework uh you know that's the essence of the framework but it's not where you get the most value out of
00:05:58.639
testing uh this happened to me a lot in the Java world we had tons and tons of models or or business objects that were
00:06:06.120
very well tested but the controllers were a disaster because it was pretty hard to basically even after having a
00:06:12.599
pretty well tested model layer to test integration between the controllers and the models and the views well let's not
00:06:19.280
even talk about the views that that typically is the Vietnam web applications that's where you're just
00:06:24.520
throw your feet up in the air and say forget it so bdd behavior-driven development
00:06:31.000
the idea is to reverse the tendency of us testing the smallest units that stand
00:06:36.160
in isolation and start from the outside in so there's a lot of bdd testing
00:06:41.919
Frameworks that have evolved over the years and by far my favorite happens to be arsp uh there are arsp clones in
00:06:49.400
pretty much every language out there uh the same thing as as you have you know rails clones in pretty much every other
00:06:55.120
language you also have arsic clones in there
00:07:00.879
and one of the things that I mentioned before is that integration testing it's pretty damn hard and it's it's the
00:07:07.000
hardest in the middle layers of the application for example between the controllers and the models in between
00:07:12.080
the view and the controllers and what we try to do with behavior-driven development it start at
00:07:18.199
the view and complement those tests at the model and live leave the stuff in the middle as the wild west until the
00:07:25.240
application solidifies because testing in that area actually becomes pretty expensive
00:07:30.400
because those are very uh fragile and brittle tests because the application is
00:07:35.560
in flux all the time and when we started we we had this Mantra in our minds that we wanted to do you know 100% code
00:07:41.879
coverage and we paid dearly for that every time that we had a 100% code coverage application on uh January in
00:07:49.879
February we had a 40% code coverage application with 60% of broken tests
00:07:55.280
that nobody wanted to refactor so we learned that to start at the edge of of the equation and I'll show you in a
00:08:01.680
second how we do that so just to how many of you work with rails on the daily basis or you know you want to work with
00:08:09.039
rails on a daily basis okay that's that's a pretty big majority of everybody here just to refresh your
00:08:14.280
memory uh we have traditional you know request handling in uh rails now I'll
00:08:20.240
try not to look at my own screen here because I have it right here I call that the reverse weatherman it looks really weird in video too so we have the view
00:08:27.520
that's where we want to concentrate our outer layer test testing and as we're testing in there we're basically going
00:08:33.640
to assume a lot of things about the inner layers of the application until
00:08:38.680
you get to the model it's okay to to actually flesh out the models in there so you basically have the two ends of the equation agreeing with each
00:08:47.519
other and I put a little U diagram together of what I think uh things
00:08:52.880
should work like so at the top you see that I have number one it's basically
00:08:58.640
write a failing acceptance test and by that I mean mimic something that the
00:09:04.040
user does so the user is actually putting some data in some edit field uh
00:09:09.079
they're pressing an in uh they're pressing a submit button they're expecting to see something on the screen
00:09:14.360
uh a popup comes up a flash message appears that's the type of things that we want to test at the outer layer of
00:09:20.040
the application uh so and I call that acceptance testing because it's between your application and the user some of
00:09:27.880
the tests in there would be the things that you want to have as a checklist for the user to say yes that works yes that
00:09:34.720
behaves as expected uh but not every acceptance uh not every test at that
00:09:40.800
layer becomes an acceptance criteria bound test because some of them are a lot of uh edge cases that the user don't
00:09:47.120
really care about they those the ones that they don't care about we care about it's because we want to be you know warm
00:09:54.000
and fussy about the application that we wrote so you notice that inside uh
00:09:59.399
between the views and the controllers in this example I have one view maybe talking to two controllers um at that level I do tdd
00:10:07.399
but I I do tdd to flesh out the controllers and the only reason I'm doing tdd at that level is because I
00:10:14.000
don't really know what I'm doing I want to figure out what the controller should do and that's why I use CDD in those
00:10:19.680
inner layers but still the thing that's dictating the whole process is that outer acceptance testing that I started
00:10:25.240
with the same thing happens when I get to the models One controller might be using multiple models and then at the
00:10:30.920
model level now I'm fleshing out designing the API of the models by using tdd so if you look at the right hand
00:10:37.680
side of the diagram notice that I have this uh Arrow going down to the acceptance testing and
00:10:43.560
returning that is the big outer loop then inside of that there's going to be a lot of mini Loops testing integration
00:10:50.639
testing between the controllers and the models and then at the model level I have tiny little you know tdd Loops to
00:10:57.519
actually flesh out the models so let's talk a little bit about bdd and and why do we call it Behavior
00:11:04.279
driven development when I started doing tddd and in unit testing I couldn't see really the difference between the two
00:11:10.680
sometimes I thought well you know I I if I'm using test unit is it unit testing if I use RSP it's by definition
00:11:17.399
integration testing or you know an outer layer testing and that's not the case it's it's really what's important to the
00:11:23.600
user and what's important to the user is what they can perceive and that's where uh eventually we'll see how capy Bara
00:11:30.480
comes into the equation so Behavior driven development uh it takes tdd and
00:11:36.600
focuses tdd uh to get maximum value for stakeholders and that's a very blown
00:11:42.560
enterpris statement that I think I pasted from somewhere but what it means is that you
00:11:47.600
really want to test the users kicking the tires of your application and sometimes you don't even know what those
00:11:53.560
tests are going to be uh one of the approaches that we have is that our designers will actually uh come up with
00:11:59.320
a UI that that that the users believe it's what they need and then we see them
00:12:04.839
using it and we realize this is going to be impossible and that UI evolves Just Between the designers and and the users
00:12:12.000
as a conversation there's not even tests to back anything up but once they get to the point that they have a Mei workflow
00:12:18.000
in their mind that actually makes sense that's where we jump in with our our capy Bara acceptance uh driven
00:12:25.600
testing so bdd also implies that you're going from the upsite in and also
00:12:31.399
implies that you're refining the language you're refining the language to be something that the users can
00:12:37.079
understand in bdd we use uh specifications uh in arpec the spec part
00:12:42.760
of arpec it's specification uh show of hands again how many of you are using arsp to test your software okay so we
00:12:50.120
can probably move faster than this now one of the things that uh
00:12:56.720
sometimes it it feels weird when you're using um a framework aspect when you're fleshing out a model it's that you're
00:13:03.240
wondering wait this is way too far away from the user but again it's just the framework allows us to write the same
00:13:10.320
unit test that we had before with something like test unit in a cleaner fashion all right so what to
00:13:17.279
test only the things that matter to the user typically would be the reflection of a user story or if you're you know
00:13:24.680
using use cases it would be probably a a scenario of a use case uh where to start
00:13:30.680
from the outermost layer in the in the case of web applications it would be a web page most likely a
00:13:38.720
form uh what to ignore everything else and again I emphasize to ignore the
00:13:44.040
stuff in the middle because that's a stuff that's in heavy flux that you need to ignore until it solidifies the whole
00:13:50.440
architecture and design of the app so typically we have user stories
00:13:55.560
that look like this we have as a role I want to uh accomplish some goal so I can benefit in certain way and with arpec in
00:14:03.720
in most of the bdd Frameworks it translates pretty much directly to given some State some role in some State uh
00:14:10.680
when I an action happens or when a specific event occurs I want to benefit in certain way from the application like
00:14:16.639
the application might be returning a a new page with some set of data that that I'm
00:14:21.920
expecting so now we're about to kick the tires with the tutorial so we're going
00:14:27.320
to do a little tdd tutorial with arpe uh it's going to be focused at the unit
00:14:32.839
level so I I don't want you to be Mis misled by that because I just want you to get the mechanics of arsp it looks
00:14:38.120
like most of you have used arsp before so we might be able to move really fast through this just to give you a couple
00:14:45.320
backgrounders on arpe it is by far the most popular bdd framework uh for the
00:14:50.839
Ruby platform um it's been around for a while now I mean this is it's it's it's going into past the toddler
00:14:57.600
stage and it provides a DSL that allows you to test in the language of bdd
00:15:03.120
another nice thing about arsp is that a lot of different Frameworks integrate with rspe by providing matchers uh that allow you to express
00:15:10.519
something in the language of bdd so here's a a very quick example of
00:15:16.839
what an RP specification looks like and in here at the uh the contrast
00:15:22.360
is a little bad in there but the whole thing is called the example group so that describe block is an
00:15:28.199
example group inside I have specific samples examples or specifications in in this one I have
00:15:35.839
I'm describing uh a score in bowling um it returns zero for a gutter game uh
00:15:41.880
notice that down below I have an expectation so we set up some State we
00:15:47.440
produce some event or action and then we see what the specification uh it's it's looking to validate so in this case I'm
00:15:54.759
expecting that the bowling score uh to be equal to zero now for those of you that have been using rspec for a while
00:16:00.759
the uh spec syntax it's fairly new I mean probably the last year and a half or so uh you got probably used to seeing
00:16:07.440
shoot do something or other uh spec seems to be the new kid in the block and
00:16:13.199
most uh tutorials most books are moving towards spec because it kind of blocks
00:16:19.759
your expectations in a nice uh block of code and that equals zero it's the
00:16:26.759
matcher and once we jump into cap bar you'll find out that there's a lot of matchers that allow you to basically
00:16:32.000
deal with with things that happen on a web page now arsp has a bunch of different
00:16:40.040
uh matchers to do pretty much every type of comparison you can think of um from booleans to checking if something
00:16:46.759
actually exists or not uh expectations of raced errors or specific errors being
00:16:53.240
thrown uh and it also creates a DSL over specific methods that you have so if you
00:16:58.639
have a method called um exists question mark you can say
00:17:07.760
expects to exist and there's also a lot of nice
00:17:14.679
collection methods there's also uh regular expression matchers and those are pretty useful too when you're dealing with a web
00:17:22.319
application so again let's jump into tdd with rspe tdd not really about testing
00:17:28.720
uh every time that I used to hear that phrase I'm like what do you mean it's a testing framework I write I'm writing
00:17:35.240
tests the the key point in here is that when you're not quite sure what that class should do tddd might help you
00:17:42.320
clarify your thinking about it so tdd is not really about testing it's about design um not all of your tests would be
00:17:49.440
about design some of them would be about collaborating some design that you already had preconceived in your mind so it's a combination of
00:17:55.760
both obviously tdd leads to cleaner code and separation of concerns every time
00:18:01.760
that I write something without following tdd I end up with way more code than I needed and one of the tendencies that
00:18:07.400
programmers have is that we like to abstract and simplify so somebody tells us hey you need a method in this
00:18:12.720
controller to do this they walk away from you for two weeks they come back and you wrote a framework or a library
00:18:19.120
not what you were asked to do I tend to do that all the time it's like oh yeah here's a a gem that I created because
00:18:24.559
you asked me to to validate an email in a controller so tdd also curves that
00:18:30.720
tendency that we have to basically write too much over design over engineer
00:18:37.360
things now one of the things that I really like about tdd is this kind of Zone that you get into once you have tdd
00:18:44.280
down and I'm I've been doing tddd for about 10 years now and I'm by no means an expert some days I'm like I I don't
00:18:51.840
think I can tdd anything today I'm just going to hack it on the IR on IRB or on the rails console and then I write a
00:18:58.320
test about but that's actually perfectly fine for example IRB or the rails console it's a great learning
00:19:04.039
environment for you to kind of get uh your whereabouts of how to put that test
00:19:09.640
together to start the tdd cycle so sometimes I do that I'll be playing with some API that I don't know anything about on the rails console for a couple
00:19:16.520
hours before I write the first test the good thing it's uh that I like about the rails console in IRB is that I don't
00:19:22.240
commit that code to anywhere when I do it in an RB file I have this tendency I'm just going to check it in because I
00:19:28.240
don't want to lose it and now you have code that it's Legacy code the moment you push that into into your G
00:19:35.679
repository so in um it also gives you this lightweight rigor so you're basically it's making development really
00:19:42.200
goal oriented uh and when you have you know we're a consultancy so when you have customers being goal oriented it's
00:19:48.679
actually pretty good for the customers in tdd we have this Loop that
00:19:54.120
we call Red Green um refractor and I have a little illustration of uh red green refactoring
00:20:00.720
here so you start with failure this is probably the only activity in life where you with starting with failure is a good
00:20:06.679
thing like sometimes I'm I'm sitting there trying to come up with the test and when I finally have the test and I
00:20:12.799
run it and it breaks I'm like yes broken test and it it's you know if you were to do that 20 years ago people would be
00:20:19.000
like what is wrong with him so then green how to arrive to green and now again that it takes it takes a
00:20:26.200
lot of practice to arrive to Green without doing too much uh and but also not being dogmatic in
00:20:32.440
doing way too little sometimes we do very silly things and we do like a you know eight Loop tdd cycle to come up
00:20:39.840
with a equals b or something like that a simple assignment so you all as you get better with tdd you have to balance
00:20:46.280
those forces and then once you have the minimal possible thing that would work
00:20:52.159
that would satisfy that test then refactoring means making it better when you refactor sometimes new things spr
00:20:59.280
out of the the whole thing those things that Sprout don't write code for them write test for them so you basically you
00:21:05.360
restart your tdd cycle with the new ideas that came out from understanding what you just
00:21:10.640
wrote All right so for this follow along what I want you to do first is to create
00:21:15.960
a directory uh you can call it whatever you want it to call uh to be called I
00:21:21.000
called mine rspec follow along and then I'm going to CD to that directory and create an rvmc uh rvm RC
00:21:29.640
file if you're using any other um Ruby uh version manager or gemset
00:21:37.600
manager uh do the equivalent that you would do with that one I'm also creating um a gem file and
00:21:46.360
that gem file is going to have the very simple contents that I have in here basically I have one simple group called
00:21:52.840
test and inside of that I'm declaring the gem arpec once you have have that in place
00:21:59.720
we can actually uh run the bundle command you might need to install gem install uh
00:22:05.200
bundler uh if you don't have bundler already in your system and once you have bundler installed we can bundle the
00:22:11.000
whole thing and we should have now a directory ready to be played
00:22:27.520
with
00:22:37.840
now if you get stuck and you see somebody next to you that looks like they got it working just peek over their
00:22:43.520
shoulder since uh we don't we don't have much in terms of assistance today so I'm
00:22:49.039
G to try not to step step away from the
00:22:57.440
podium all right let me see show hands who's got the directory
00:23:04.039
going okay we getting pretty damn close
00:23:12.279
awesome okay so uh once if you're using uh rvm you're going to have to CD out of
00:23:17.600
the directory and CD back in so it recognizes the rvm RC file and then we
00:23:23.200
can run bundle if you hav't install bundler you probably have to install bundler too uh you can see some of the
00:23:30.279
dependencies that that rspe will pull in and I believe that my rspec version
00:23:36.919
it's 1 Point uh behind but what I have in the running demo it's actual 2130
00:23:44.159
which I believe it's the latest one
00:23:53.240
2131 okay so let's start our re red green refractor uh loop with the very
00:23:58.480
very the simplest possible failure we're going to build build this mini shopping cart pure Ruby right now and I wanted
00:24:04.760
you to start with the card the a card spec which is going to be in a card spec RB and it's going to have just a
00:24:10.679
described word a described block that specifies a class that we don't have yet
00:24:15.960
cart and it's going to be an empty body block of
00:24:27.360
code
00:24:37.440
now obviously there's a lot of places we could take a shopping cart but we're going to keep it pretty simple so we get the mechanics of our spec so we can jump
00:24:44.000
freely into capy bar without worrying about the rspec
00:24:53.440
mechanics so with the carspec in place we can actually run the
00:24:59.120
test uh typically you will be typing rspec uh you can probably just type
00:25:04.559
rspec without the spec U command in there and you should get that we have no
00:25:11.320
card class so in in our case this is possibly the simplest failure that we
00:25:17.039
can get now in practice I I don't always use the simplest failure that I could
00:25:23.399
get sometimes I I fast forward a couple tdd Cycles in my mind the trick here is
00:25:28.640
not to fast forward too far where you can you start basically losing track of some of the dependencies that might be
00:25:34.320
in there so early on it's okay to fast forward later on you will pay for
00:25:41.000
it now notice that I have a hint in there that says that if you have a failure when you have you don't have any
00:25:46.320
tests typically means that you're basically uh missing a test to account
00:25:51.440
for that failure because a failure it's a failure and you should be able to test
00:25:57.279
that a failure exists so in the next section now I'm creating
00:26:03.360
my empty C class we goes with my described uh card
00:26:08.679
block that happens to be in my card spec RB and notice that I'm doing a require
00:26:14.399
relative since we're not in rails things that don't get required automatically so I'm doing a required relative to bring
00:26:20.320
the C class that's supposed to be in my lip directory now if you go back
00:26:33.240
I probably missed this but you were supposed to put the card SPC on on the spec directory so uh if you didn't do
00:26:39.720
that go ahead and create that directory and move it there I I totally missed that in my slides but now that we have an empty
00:26:46.360
card and we have a carpc that's empty we can actually run rspec again and
00:26:52.799
basically get a zero failure arpe run but notice that we also have no examples
00:26:59.320
but before we had a failure so one of the things that I like to do with some systems is to make sure that that
00:27:04.679
failure is explicit in my system now and that's what I'm doing um further down
00:27:10.919
the line so now let's tackle our first realistic test in here and the spec is
00:27:19.360
going to verify what happens when we get a brand new card and notice that I have
00:27:25.080
now an extra block called context that says cont some string and another block
00:27:30.399
of code now arsp allows you to daisy chain all this initial states of what
00:27:37.039
you're testing in a very clean fashion so in here I'm saying a card a new card
00:27:42.840
contains no items inside of the it block I have an expectation that the instance
00:27:49.799
variable card should be empty now uh this is making a lot of
00:27:56.240
assumptions those assumptions it's the design part of the equation comes in I
00:28:01.600
made in my mind the design decisions that the card is going to be something
00:28:06.760
that that responds to the empty method so empty question mark it could be a
00:28:11.799
hash it could be an array but we haven't gotten there yet but at least we made one decision and this is a API design
00:28:18.799
decision I also made the decision that I have an instance variable named cart so
00:28:24.799
you start coming up with this many decisions that eventually coales into a real
00:28:32.240
design so I'll give you guys a couple seconds to flesh out that
00:28:41.080
spec so again I'm expecting my cart to be
00:28:48.960
empty if I run arsp now you will see that I have one example and one
00:28:56.279
failure the failure is is that we don't have a method empty on the card instance
00:29:03.240
variable because it doesn't exist so again we're inching forward towards having something real in there but and
00:29:11.360
one of the things I really like about tdd is that that this micro process while running tests allow you to think
00:29:18.039
in a much more organized fashion about what you're building and once we go out to the outer layer testing it will make
00:29:24.600
even more sense so we arrived at a real red State
00:29:30.919
we have failure and that's a good thing now we can start writing the minimal amount of code to pass that's that's
00:29:36.880
that test so again with bdd one of the the main ideas is that you want to get the
00:29:43.080
words right because those words reflect your intent in the code and if you get them wrong eventually somebody's going
00:29:49.399
to refactor your code to do the wrong thing so get the words right from the get-go uh you you probably notice that
00:29:56.480
when we run the test the output of arsp says said card a new card contains no
00:30:02.240
items that doesn't read really well that's the beauty of aspect you have free flowing strings in there to
00:30:08.279
basically make sure that the output of the test reads like something that makes sense so I'm refactoring the test a
00:30:15.760
little bit to basically say I'm adding a little bit of programmer lingo in here because I want to know which entities
00:30:22.559
I'm dealing with I'm saying describe an instance of passing the class card by
00:30:28.600
actually passing the class object in there ARP knows that you're dealing with that
00:30:34.720
card class and it's expecting that C class to exist the next con con uh context block
00:30:42.039
says when new do now read the the green Parts only an instance of card when new
00:30:50.760
it contains no items or contains no items and that's what we're looking for we're looking for this fluidity that is
00:30:56.320
going to come out with a statement of truth about our system and it's going to reflect the design that we just just
00:31:02.720
implemented so a little bit of refactoring to get the language right and uh again we we run the spec
00:31:09.519
and now we see the language uh appearing correctly on on our
00:31:16.200
output now the next thing we want to do uh it's implement the very simplest
00:31:23.639
possible thing that we can do to pass this but first I want to address what I was uh talking about a few slides ago I kind of jumped the gun in there it's
00:31:30.039
that we had two failures we had an explicit failure uh the assumption that we had an empty method available and an
00:31:37.679
implicit failure the fact that the instance variable card was not there to begin with and this is probably a good
00:31:45.279
point for discussion um one of the things that we can
00:31:50.639
do let's address the fact that the text fixture didn't exist so basically our
00:31:56.000
card instance variable was not round so I'm going to create a very simple one by saying art equals cart new uh and where
00:32:03.480
should I put that so when I started using arsp basically you will just put it right on top of that expect line and
00:32:10.440
you would have an object to test on that expectation the idea of having to
00:32:16.639
describe blogs is to gather specific tests again one state of a class uh that
00:32:24.960
you're under test so in our case we want to test a brand new card and that's what
00:32:30.799
we what we want in here it's to have a before block that tests everything that
00:32:38.080
that sets up everything so now Noti in here that my test it's an instance of
00:32:44.320
card should be properly uh properly initialized so now that that uh that
00:32:49.480
implicit failure I made it explicit by writing a test about it and you will see things like this sometimes with u when
00:32:56.080
you're testing against let's say an integration test test that talks to some U mock web
00:33:01.320
service and you at least want to know that there's a connection between your test in the mock web service because in
00:33:08.399
the real scenario you want to test that you have a connection between your app and some external web service so again
00:33:15.080
sometimes these explicit failures where you see aspect breaking means that you probably want to write a test to cover
00:33:24.880
it now we're still missing uh functionality we have uh a card created
00:33:32.279
but the card still doesn't respond to the empty
00:33:40.039
method so the first step is to initialize a card instance on a before
00:33:46.440
block so you can do things that happen before the whole test class executes or
00:33:52.039
before the specific methods in that describe block execute so in this case I'm doing a before each and the before
00:33:59.399
each means that it's going to run that line that says at cart equals cart new
00:34:04.760
before every single test there so we're effectively resetting the at cart variable every single
00:34:14.320
time how's everybody doing going too fast too slow slow down a little bit
00:34:26.720
okay so again let me recap in each one of my
00:34:33.639
describe blocks I describe scenario the scenario typically it's driven by some
00:34:39.599
initial state of what I'm testing in the case of the card I'm testing a new card
00:34:46.639
so in my before block I want to create a brand new card if I had a a scenario
00:34:52.359
that describe a card with two items on the shopping cart then it might be for
00:34:57.880
block for all those tests I would have created a card and added two items to
00:35:03.160
the
00:35:08.240
card okay so now we can really focus on the failure that's going to drive the
00:35:13.839
development of the app and I'm saying uh I'm seeing that an instance of card when new contains no items and it's fail
00:35:20.680
failing because the empty method doesn't exist now the purist in tdd will tell
00:35:26.000
you well put a empty question mark and return nil and that is the simplest
00:35:31.839
thing you can do to get past that failure uh I don't like doing that I I
00:35:37.240
think this is a point where you can fast forward a couple tdd cycles and say well I want to back my card with something
00:35:44.839
that supports the storage of the things I'm going to put in there
00:35:51.079
but just to cover the puristic approach I'm in here I'm adding an empty method
00:35:57.880
to my car that returns nil so now I run my uh test and notice it's failing
00:36:05.599
because the empty method is returning nil while it's expecting to return through so if you're going to muck it or
00:36:11.599
stub it at least make sure that the stop Returns the wrong thing to break the test because otherwise if you're dealing
00:36:18.280
with a lot of classes and it's a complex system and it's further down the road you might forget about it and now you
00:36:23.640
have a passing test for some code that it's not what it should be
00:36:31.839
okay so let's flesh out that empty method on the
00:36:42.640
card and now we can comply with the actual specification that we set out to pass by
00:36:50.000
really adding something behind the scenes so what I'm doing is I'm going to add a Constructor or initialize method
00:36:56.720
to my car class class where I'm creating this instance variable called items and items is going to be an empty
00:37:03.920
hash I'm also going to refactor that empty method by piping to the empty
00:37:10.520
method of the hash okay it's a pretty clunky implementation but that's that's
00:37:17.240
the purpose of tdd we're going to do the simplest possible thing that came to your mind at that point in time to get
00:37:22.880
things going and then we'll make them better
00:37:29.440
so once you have your cart flesh fleshed out like this so we have an initialized method and an empty method passing to an
00:37:35.720
items uh instance variable that happens to be a hash we can run aspect again and now get two tests that should be passing
00:37:43.760
two specifications that are passing so we reached that Holy Grail of tdd the Green State we don't have much to show
00:37:51.359
for but we're actually building software in a delicate careful fashion
00:37:58.720
so once you get to the Green State now it's time to refactor and in your mind there's probably about a million ideas right now
00:38:05.319
how you could make this better now early on refactorings are
00:38:10.599
going to be fairly simple they're going to be minute things as you move forward and you start
00:38:17.319
getting from unit testing into integration testing and you start also from the outside in doing uh acceptance
00:38:25.319
testing the correlations between the different things being tested becomes Higher and Higher and Higher and
00:38:31.560
refactoring becomes a science at that point that's when refactoring really
00:38:36.599
that that's where you you know build your chops refactoring code so to refactor this simple card
00:38:43.680
class that we have the first thing I'm going to do is that I didn't really like that passing of methods to the inner
00:38:50.119
instance variable so I'm going to use one of the things that actually comes in built in with Ruby which is the ability to forward something to an inner
00:38:56.920
instance of some object that you own as an object in this case uh in that's that's called
00:39:02.440
the Ruby forwardable module so I'm going to extend my class with the forwardable
00:39:07.800
uh module I'm going to define a delegator that's saying the empty method when invoked on the C class I'm going to
00:39:15.040
pass it to the items instance and now I got rid of that I'm
00:39:21.240
actually using a declarative way to pass the implementation of my inard
00:39:27.920
uh items instance variable to the outer class whether that's a good idea or not that's debatable too now we're sort of
00:39:35.280
exposing uh implementation specifics uh at least the person using the class knows that this is an
00:39:41.079
innumerable or is something that supports uh enumerable but notice the class is now
00:39:47.040
simpler it's cleaner uh and we're not basically calling a same name method from another from the
00:39:54.240
outside so with that refactoring in place I can run arpec again and now see
00:39:59.599
that I have a passing Suite of
00:40:07.240
specifications I'll give you guys a couple seconds to to catch
00:40:13.280
up say that again oh I
00:40:26.319
apologize I can't get my
00:40:33.280
cursor anybody remembers the is it option or
00:40:42.400
control control option function
00:40:51.839
8 nope
00:41:01.319
control
00:41:12.560
option mine doesn't want to go there somehow hold on let me let me bring that code actually uh in
00:41:25.440
uh look at that in antic
00:41:35.000
too so again if we go back and forth you can see that we
00:41:42.200
have and you're going to see this ratio between your specifications in in your
00:41:47.359
actual code sometimes it seems that you have more testing code that you have
00:41:52.400
production code and that's a good thing uh that that code is not for the stakeholders for your customers that's
00:41:59.800
code is for you to feel better about what you just built and to be able to come back two
00:42:06.319
weeks six months a couple years down the line and understand what's going on how
00:42:12.040
many times have you actually open a file of code and just say to yourself whoever
00:42:18.680
did this deserves to be fired and then scroll the way to the top and find your name I've done that a couple
00:42:26.119
times
00:42:38.640
so notice I I anybody use required relative before so it's it's it's kind of the new
00:42:45.240
kit in the blog when it comes about when it comes to requiring a file but it allows you to not have to basically find
00:42:50.599
out the root folder of your application and it just requires something relative
00:42:55.920
to the actual file your you're working with and you only have to do that here
00:43:01.160
because we don't have rails uh scaffold uh around ARP in the rails classes to
00:43:07.839
basically do everything for
00:43:24.480
you all right okay so let me see show hands how many of you got to get
00:43:30.040
everything working and running and it feels all warm and fuzzy all right so the the code it's all
00:43:37.400
going to be available um the next example is all in GitHub this one I still have to to uh zip up or or push to
00:43:44.079
GitHub and give you guys a a URL to access it all
00:43:51.359
right so now that we now obviously tonight you're not
00:43:58.680
going to go out and drink and party in Portland you're going to go to your hotel and do some coding so I left you
00:44:05.160
uh a few exercises for arsp to basically flesh out that shopping cart and I better not see you at the
00:44:11.440
bars okay uh they're on um Dropbox there's a
00:44:18.520
URL on the front I'll show again and uh they're also on the uh Ruby com
00:44:25.559
tutorials. comom website railcom tutorial.com
00:44:32.760
here let let me quickly show you guys that link so you guys have it and I apologize again because it's a very
00:44:38.880
lengthy Dropbox uh URL actually let me uh copy it and try
00:44:47.040
to bitly it is that a an actual
00:44:56.040
verb
00:45:18.079
somebody paid billions of dollars for this company and it's taking it like what a minute to shorten a
00:45:25.960
URL
00:45:39.640
let's see who
00:45:46.720
wins uhuh there is a tiny
00:45:53.400
url url that you can use
00:46:03.359
so once you get that then will jump into copy
00:46:11.480
bar well I don't know if this will work by putting the zip at the
00:46:23.079
end yeah this one it's a it's it's a PDF the other
00:46:28.119
one the other one it's that do zip and that is just the whole project uh but
00:46:34.040
it's the one that we actually going to work with with capy bar not the one you just did all right so uh I'll let you guys uh
00:46:41.720
grab that and let me switch now to the capy bar portion of the
00:46:51.880
show so again if you have some free time tonight uh there's a nice uh set of ECT
00:46:57.200
labs in there to complete it should take you like all of 15
00:47:02.400
minutes all right so let's talk about now Behavior
00:47:14.520
yes I'll stop by at the end and we'll take a look at it okay so Behavior
00:47:19.720
driven development with capar so now I I don't want to mislead you with that arsp
00:47:24.920
example because it is a unit testing example is just showing you the the mechanics of tdd for to do real bdd you
00:47:32.880
want to go out to where the user lives and that's the browser so proper acceptance uh test
00:47:40.760
they should treat the application as a blackbox that means that they should have no knowledge of internals of the
00:47:45.920
application the one place where I sometimes break that rule is that I might mimic some JavaScript behavior
00:47:53.839
from capy bar directive but other than that I try to treat the application as a
00:47:59.800
blackbox uh which means that you should they should know as little as possible about the app in how it
00:48:07.359
behaves so it's all observation driven State driven
00:48:13.280
testing now uh jeff which was here just a second ago um this is where I got that
00:48:18.800
that uh that idea that you really want to test at the outer layers and at the
00:48:24.280
model layer and leave the stuff in between untouch until the application
00:48:34.559
matures hey I I copy and paste it from your material too so thanks
00:48:39.599
buddy so capy bar it's a lightweight alternative to cucumber how many of you have used
00:48:45.520
cucumber okay how many of you like cucumber I don't like the damn thing um
00:48:52.880
I I'm I'm with dhh on on that camp which I think it's an extra layer of abstraction uh for a mythical unicorn
00:49:00.720
with wings figure that doesn't exist which is the actual user that cares about looking at your tests they care
00:49:07.319
about seeing the Behavior live and the acceptance test is for you to verify
00:49:12.960
that once they said yes it works it continues to work over time
00:49:21.920
yes yes that is scary that is an a Very scary
00:49:28.480
thought yes so yeah I mean I I try and actually in my team I have some folks that really
00:49:34.920
love cucumber that they they really like using girkin and cucumber and that's where they live I like to have the
00:49:41.160
control the power Ruby at my fingertips to be able to express my test and the
00:49:46.400
output of running the test it still looks pretty and it's either going to be green or red and that's all the end
00:49:52.960
users really care about so copy bar automates your browser
00:49:58.000
basically it it it's a remote control from your application test Suite to control browser
00:50:04.760
actions and the idea is that you want to simulate how the real users would work with the application now if you take
00:50:10.960
this to the obscene extreme you basically go into a large corporation
00:50:16.559
where they create selenium scripts to for every possibility I mean they really just random click things and put random
00:50:22.680
text in boxes and that's okay that's that's okay to shake shake the application to see if it breaks under
00:50:28.079
you know bad input and things like that but it it's really not the type of testing that we're looking for to drive
00:50:34.680
the design of the application the design of application it's mostly sunny day scenarios it's mostly what would happen
00:50:41.280
when the user does what we expect and how can we assure that the application responded in the way they expected the
00:50:47.640
application to respond so uh by default capy bar is
00:50:53.920
agnostic about how it controls the browser and it uses a rack test to control the browser rack test gets into
00:51:00.319
that HTTP layer in between uh the browser and your application and mimics
00:51:05.760
requests to your application so it's sort of a headless browser uh so you don't really see anything happening uh
00:51:12.960
that is really good because it's fast so you can run your integration test or your AC acceptance test in a CI
00:51:20.559
environment and uh you don't really need to have a a browser available that is
00:51:25.960
actually going to appear here uh on that CI machine which is probably not a good thing uh you can also what we use it's a
00:51:32.920
phantomjs which it's a real browser but a headless real browser uh and so that
00:51:38.520
will be above that layer uh that you have with rack test uh there's
00:51:44.440
also uh selenium support built in and webkit support so in the examples we're
00:51:51.119
going to do we're going to be using the selenium support which nowadays under the cover
00:51:57.720
he uses a web kit driver so it's sort of like a matrioska do approach to testing
00:52:04.160
drivers so like I mentioned before many developers do not want to bother with cucumber I'm one of those I think it's
00:52:09.920
just too much abstraction on top of what I'm trying to do uh so I want outside in
00:52:15.240
testing with the power of Ruby and not some weird DSL that that doesn't match the way I work every day uh there used
00:52:22.640
to be a well there's still a project called stake that integrated rspec with copy bar and as of two years ago or
00:52:29.839
three years ago the capy bar project said hey everybody's using capibara via stake let's just mix the whole thing
00:52:36.280
into one so now capy bar uses the same stake syntax to drive the
00:52:44.400
test I mentioned capy bar uses the rack test uh driver by default so we're going
00:52:49.640
to change that to basically use um the selenium driver one of the things that
00:52:55.920
rack test can do it's mimic JavaScript behaviors or deal with JavaScript at all
00:53:02.559
yes what the
00:53:08.559
advantage so rack test it's going in between where the browser is and where the application is talking to the HTTP
00:53:15.599
layer directly without having any uh of the standard browser uh Communications
00:53:21.599
in there they're all post and get request so it's it's really the same thing but your basically grabbing the
00:53:27.319
HTML as it's coming out of the application and not letting it uh sit in
00:53:32.720
the browser and then grabbing the dumb from the browser which we all know that there could be differences in
00:53:38.599
there so it is really fast and sometimes we start with rack test or or with uh a
00:53:45.400
headless browser like phantomjs because they're really fast uh when we move to a
00:53:50.760
CI environment we also do that it's completely headless but when I'm developing uh I like to see the browser
00:53:56.720
come up and I like to see things being dropped down and value selected and things being dragged and dropped uh it
00:54:03.000
it really helps you visualize you know see this fast forward movie of the application being
00:54:10.319
used and like I mentioned there's the selenium web driver and the capibara web kit driver so we'll be using selenium
00:54:15.880
web driver the uh nice Folks at thoughtbot put a cheat sheet for
00:54:21.079
capibara because every time that I'm using capibara I have to look up the documentation to find out where things
00:54:26.920
are so they put a really nice one together it's a a two-page PDF uh the URLs at the bottom uh that I use all the
00:54:34.000
time to basically figure out what I need to do but as you can see there's uh methods
00:54:39.200
to do navigation there's methods to check things on the page uh whether there's content in here whether this CSS
00:54:46.119
it's available or applied to something uh you can basically scope searches you
00:54:51.280
can say within this div that matches this CSS class selector then look for a button that looks like this and click
00:54:58.920
it uh you can uh have weights and one of the things that you're going to find frustrating is that every time that you
00:55:05.680
have a lot of Ajax functionality you become a master of figuring out when to wait and for how long uh and then trying
00:55:12.520
to find the breaking point between waiting too little because in Breaking the test but not waiting too long and
00:55:19.280
slowing down the whole test Suite uh obviously you can you can deal
00:55:25.599
uh interact with with the with the dumb at any point in time you can click things you can trigger events you can check whether something is visible uh
00:55:32.760
you can fill in forms uh check uncheck uh check boxes in radio buttons and uh
00:55:39.440
select click buttons there's also a very nice a feature called save an open page where you can save the HTML markup at a
00:55:47.720
specific point in time uh there's also a a little bit of a trickery to actually take a a screenshot too of the
00:55:53.880
application so you can really automate your test to oh something broke save the HTML so I can go and manually inspect
00:56:00.599
the HTML or um everything seems to work fine but how about the look and feel so
00:56:06.359
you can take a snapshot of the screen and maybe somebody can manually look at that that picture and be like well on
00:56:12.520
i7 who whoever uses that anymore everything looks horrible which typically is the case uh so again it
00:56:19.920
it's a has a lot of very nice facilities not all of them are uh very easy to access you have to do a little bit of a
00:56:26.319
back overflowing uh but but they're
00:56:31.400
there okay so we have a very simple rails application and the application
00:56:37.480
that I put together uh basically uses the device gem to add some of the
00:56:42.599
authentication login pages to a to a barebones rails application with a little bit of a Twitter bootstrap in
00:56:49.160
there just to make it look palatable uh I'm also adding a few uh static Pages
00:56:54.359
using the high voltage gem that allows you to basically embed static pages into
00:56:59.680
your app in uh without having to create a whole controller hierarchy to serve
00:57:05.160
your own pages that are just static so if you have git install
00:57:11.680
um I would like you to clone the repo sitting at um my
00:57:20.039
company's G GitHub account and it's called learn rp. copy so you might as
00:57:25.480
well just go to that URL and then copy the G URL from there unless you can copy
00:57:30.640
and paste from the slides which sometimes with PDF might be
00:57:52.720
questionable so I'll give you guys a couple seconds to clone that repo and then we'll have some fun with
00:58:12.640
it yes there a question about using capara when you're when you're using capar do you recommend just uh scripting
00:58:20.599
all the user interactions against the page or would you be thinking of creating uh
00:58:27.960
objects so there's a pattern called the page model uh pattern where you really
00:58:33.760
encapsulate all the the tests all the interactions with a single page uh in in
00:58:39.440
one place um in for single page applications where you have let's say a
00:58:45.280
rails application that's using something like backbone and you have five single page applications living in one rails
00:58:51.000
app that's that's a pretty good pattern if you have uh which this doesn't happen very often anymore more if you have a
00:58:56.960
very long navigation uh driven app where you going through let's say 10 different URLs to to get something done um which I
00:59:05.240
don't think any of us do anymore but let's say that you're building software for the IRS or something like that and
00:59:10.480
you have a 20 step wizard it's the IRS they'll probably do something like that
00:59:15.680
just to torture you uh in that case then the the page uh object model kind of
00:59:20.720
breaks down because you really want to test uh across a large collection of pages to get that
00:59:26.720
expected Behavior Uh of the application in in those in that
00:59:32.119
context I guess the question is actually a bit more simple than that is whether or not you would do a visit group page
00:59:38.799
or would you do a click whatever link I mean it depends if if there's some state
00:59:44.599
that is going to be so let's say that I'm using the bookmarks the HTML 5 bookmarks API well if I do a navigate or
00:59:51.000
if I do a click it might be different so in that case yeah I would pick one or the other based on the context that I want to I have ahead of time okay so you
00:59:58.280
have to yes yeah all right so I'm going to assume that everybody has the uh get clone get
01:00:05.039
repo clone no slow 40 people cloning a repository over
01:00:13.079
a Wi-Fi connection yeah all right while that is happening
01:00:20.760
but everybody has it typed in there so it's it's it's it's crunching okay good
01:00:27.319
all right so I'm going to show you basically what the app does first um once you get the the repo clone I
01:00:34.799
want you to CD in and out of the directory so rvm basically recognizes that we have an rvm RC file I want you
01:00:41.160
to uh uh do a gem uh install bundler if you don't have bundler and then go ahead
01:00:47.240
and bundle the whole thing and then you can launch it with rails uh s but I'm
01:00:52.280
going to do that in here so you can see what I have
01:01:03.160
so this application and just to give you a preview here if I run the tests that I
01:01:08.520
have for this application I have two passing tests right now and everything else is pending and that's really what we're going to be fleshing out uh in the
01:01:15.799
application but as you can see the browser was launched in there just for those two simple tests that we had in there um so let me launch the
01:01:23.280
application you can see what it does
01:01:34.559
I hope you guys copy that URL because I'm moving away from the page so all right so here's our Simple app uh
01:01:41.680
it has uh it's Style with Twitter bootstrap because who doesn't do that
01:01:48.280
nowadays and I have a homepage it's all Laur
01:01:53.880
ior pck Latin in an about page I have a sign
01:01:59.480
up if I go to my
01:02:06.839
signup I can sign into the simple app
01:02:11.880
and that will take me to the oh if I were to oh I already
01:02:17.279
registered let me switch that to uh
01:02:23.599
Gmail whoever owns a doc please get out of the
01:02:30.599
room okay so let me sign in into my
01:02:35.960
application and that takes me to the homepage notice that there's a flash message using the uh Twitter
01:02:43.599
bootstrap uh alerts and I have a profile page for the
01:02:49.240
user where you can go and change your username and password this is all courtesy of device so device basically
01:02:55.880
gives you all this stuff for free and the home and about pages are just static
01:03:01.119
pages that I'm serving with high voltage basically what high voltage does it's create a Pages controller that grabs the
01:03:08.400
default URL and if it matches one of the pages that you have store it will serve it very simple I also have a sign out
01:03:16.039
page uh a sign out uh a sign out button
01:03:21.400
to log out of the app okay
01:03:28.960
so you guys clone that repo excellent okay so like I mentioned
01:03:35.480
before you want to CD in and out of the application uh you want to bundle install uh R DB migrate and then reg DB
01:03:42.400
test prepare if if you guys work with rails on a daily basis I probably don't have
01:03:47.720
to tell you what that means uh but we're really want to uh I'm using the SQL light database so this is just creating
01:03:54.000
the DB files that we're going to be playing with because it would be cruel if I make you actually have a database a real database install on your systems so
01:04:01.839
if you uh launch the application you should see the pages that we uh just I just showed you and I have those on the
01:04:08.200
slides too but I'm going to move uh through that and get to the meat of the capy Barra section so if you
01:04:16.720
were to run rspec spec on the application directory you would see that
01:04:21.920
there this is really hard to see isn't it black backgrounds always get me but see
01:04:29.200
I I use white backgrounds on the rest of the slides but black backgrounds on the uh on the actual
01:04:50.920
code I just want to be able to read what you so we have uh
01:04:56.440
two specs that are passing and those are very simple specs at the model level all
01:05:02.119
the real capy Bara specs are
01:05:07.359
pending now this is a little easier to read the two specs that are passing are are very simple specs that I'm using a
01:05:13.960
Shuda matchers to basically test that my user object actually validates the
01:05:19.880
presence of an email and also validates the uniqueness of an email uh if you are
01:05:25.240
used to testing your own validators you typically will create an object without the email and then make sure that it's
01:05:31.200
invalid and then check the errors hash to find out that there's a message there that tells you that it needs an email so
01:05:37.520
the Sha um uh matchers basically do that for you in one a one liner so it's it's pretty nice uh but I really just gave
01:05:43.640
you that so there would be something that actually passes everything else it's a pening
01:05:49.640
spec and here's the first one that that we have it's a non-javascript capy Bara specification
01:05:56.160
uh notice that it's in the context of success and then before I do
01:06:04.799
before this uh this is about sessions about logging in so this is when I log
01:06:09.839
in successfully before I want to sign in I want to try to sign in then I want to
01:06:15.680
check that there's a welcome message being displayed so remember we saw that flash uh message in there or that welcome Banner actually I think it was a
01:06:22.359
an H1 and then I want to make sure that the correct links are present now so if
01:06:28.279
I'm not logged in I should see the sign in and sign up and if I'm logged in I should see the sign out
01:06:35.160
links all of them are pending the two specs that we have here are pending and we have nothing to basically set the
01:06:40.920
stage for the test on the before block and you will find that under the
01:06:46.359
spec directory under features now your user acceptance testing goes into that
01:06:52.880
features folder when you're using rspec and capy Bar
01:06:59.000
combination now the first thing I want to do is try to log in and I'm going to assume that I have a correct and valid
01:07:06.880
username and password so I'm filling in the email field with something called
01:07:13.359
email and we'll see what that is in a second and I'm filling in the password field with a password then I'm clicking
01:07:20.240
the signing button so that is setting the stage for my test now let me go to
01:07:25.319
the code and show you what that looks like in the larger
01:07:36.839
context and I'll make this a little
01:07:42.720
bigger so up at the top I'm creating a
01:07:48.039
user uh my user has an email and password um I'm using factories in here
01:07:55.920
and then I have my Jill example.com with the password
01:08:01.839
password and here's a test that you were just looking at in the context of the user sessions when I
01:08:09.119
successfully log in I want to display a welcome message and I want to show the correct navigation links
01:08:20.239
okay now to look for that welcome message I I'm using RP expect method I'm
01:08:28.000
going to expect something off the page so capy Bara makes this page object available to you so I can interrogate
01:08:34.679
that page object for certain things the simplest thing that I can do is ask the page if it has some content and you
01:08:42.359
really don't have to navigate through the page so this is a very precarious way to find content because if you were
01:08:49.679
if you were to have that message repeated in a couple places then you you wouldn't know why you're passing or
01:08:56.159
failing the test but for a simple page this would do you can also scope those searches so I can say within a specific
01:09:03.719
div or a specific Span in my page then look for some content but in here I just
01:09:09.400
went to to the whole page as a global object so I'm saying expect the page to have the content sign in
01:09:22.279
successfully and just to give you an idea let's me
01:09:30.839
uh so I obviously have a version of this that it's already fleshed
01:09:37.040
out so notice up up at the top I have my fixtures being
01:09:45.319
set before the whole set of tests I visit the root path of the application
01:09:51.799
and within the nav bar within the the element with the nav bar class I click
01:09:56.960
the signin uh link then notice that I have another
01:10:02.640
block which is the context of succeeding I further do more actions in that before
01:10:07.719
block so all this before blocks they will chain together so you might have a
01:10:13.239
very simple scenario that navigates to the page at the top level one that basically tries to sign in and um and
01:10:19.840
then once who tries to sign in with an incorrect password and you can keep on enhancing that pre that set of
01:10:26.040
preconditions to basically create the right scenarios in there sometimes it can get a little hairy so we refactor
01:10:31.880
those before and after blocks into simple methods that are easy to read so we can say oh uh sign in or attempt to
01:10:39.640
sign in with wrong password and then try to click on the register again with the same email so we also make a like a mini
01:10:47.000
DSL to deal with our before blocks which really helps in the long
01:10:52.199
run so now here we have the test where we expect the page to have the content sign in
01:11:02.199
successfully now the next test uh I'm looking for links so I want to make sure
01:11:08.320
that the right uh links are shown when the user is logged in and when he's not logged in when she he or she is not
01:11:13.840
logged in so now I'm scoping my search I'm saying it shows the correct navigation shows the correct navigation
01:11:20.520
links the correct navigation links within this napar element so you can use
01:11:25.800
CSS selectors and that's a very nice feature of uh capibara and in arpec in here so if you're using jQuery every day
01:11:34.320
you're probably a ninja dealing with CSS selectors that knowledge translates directly to writing your copy bar test
01:11:40.920
so within my nap bar I'm expecting the page but now that page is not the whole Global page it's just scope to that nap
01:11:47.760
bar uh to have a link with the title profile and copy bar it's pretty smart
01:11:53.239
by default it's trying to assume that the things that you're mentioning are the visible things of so this would be
01:11:58.800
the text inside of that H uh that that anchor if you wanted to look for
01:12:04.560
something specific like let's say has a a data Dash attribute with some value then you have to get a little more down
01:12:11.440
into the core of of the markup to to specify that but by default if you can see it capy Barra can get to
01:12:18.719
it so I'm checking for the two links uh for the profile and to be able to sign out because I'm I'm signed in correctly
01:12:26.000
and I should not have the link to sign in or the link to sign
01:12:32.400
up all right so let me show you those two in the context of the whole testing
01:12:45.400
class and since we're getting close to run out of time I'm going to just run
01:12:51.280
this so you can see what I like to experience every time that I'm working with capy Bara uh obviously when you have a very large
01:12:58.040
suite of tests you don't want to run them all at the same time but I run one specific one that I'm working on and allows me to keep on playing this movie
01:13:04.760
of what I'm doing really fast in my mind and it's it becomes really a really Dynamic approach to building your app so
01:13:12.239
I believe uh that's the master Branch oh by the way so there's two branches on that project the master branch has the
01:13:18.159
application fully fleshed out with the test all pending the testing branch has all the tests passing so if you do a g
01:13:25.159
check out testing or test test or do a git Branch you see the list of branches
01:13:30.600
you have in there you can check out the testing branch and see it all fleshed out so let me go ahead here
01:13:37.280
and uh run my test and obviously this is the
01:13:43.480
full-blown Suite of tests
01:13:52.040
running so I'm checking a bunch of different stuff uh and you can see from the specs what we're checking we're
01:13:58.080
checking that um The Flash notices show up so those are JavaScript test I'll
01:14:03.560
show you in a second how those work uh I'm showing um I'm checking the page for
01:14:09.080
navigation links all throughout uh the different activities that we're doing uh
01:14:14.800
and I'm canceling I'm checking the cancel registration
01:14:23.440
feature so now the The Flash notices it's a JavaScript test because those
01:14:29.280
flash notices are activated by bootstrap using JavaScript so for that I have to add the comma JS after the name of my
01:14:37.639
describe block notice before the that block I'm
01:14:43.600
visiting a specific page so you can use uh name routes in your capy bar specs
01:14:50.679
you don't have to put a string URL uh to navigate to something so it's very nice
01:14:55.960
uh it's also an extra layer of testing of your routes then uh we have the user the The
01:15:05.080
Flash message should be able to be dismissible by the user so what we're doing now that's that's a pending
01:15:11.440
test to pass it I'm first going to check that it's there so I'm going to say I
01:15:17.320
expect the page to have that flash message then within that alert class
01:15:24.639
which is the the div that wraps the whole thing the whole alert message I'm going to find the close button which has
01:15:30.400
a close CSS class and I'm going to click it therefore dismissing the
01:15:35.520
dialogue and after that I'm going to check that the dialogue went away that
01:15:41.120
the alert message went away so that's typically the scheme of how you go about testing something like that again all I
01:15:47.600
had to do to enable the JavaScript behaviors was to have that comma JS in my describe block and now I can say it's
01:15:54.320
a dialogue there yes go inside the dialogue find the close button click it and check that the
01:15:59.880
dialogue has gone bye-bye all right so and I think we're
01:16:07.560
coming uh down to the closing of the session and what I have left in there for you guys it's if you don't want to
01:16:13.920
jump and peek into that branch that has all the tests already fletched out you could uh try to do that yourself and it
01:16:21.199
it's it's actually a very good exercise this spec since we use device with pretty much every application uh it's
01:16:27.679
test that we carry around uh in in a more uh compact form than this but you
01:16:34.000
get the idea it's something that you you probably want to have there from time to time this is uh again it's testing
01:16:39.960
device is that a good thing it's not code that you own so that that's a good question now what test though is that if
01:16:47.080
I switch from a device version to another device version that the same things that device did for me before are
01:16:53.080
doable still and that's one thing that I like to do and I do that with open source projects too so let's say that I
01:16:59.120
have I built my application against a gem that's version 1.0 okay and now they
01:17:06.080
came up they come up with a 2.0 version well what I would do is put the two 2.0 version of the gam in there and use
01:17:12.880
their specs for the 1.0 to verify the behavior so that that gives me a checklist of the things that should be
01:17:20.120
broken now the the places that I have to look for refactorings to to perform
01:17:25.480
so uh hopefully this would uh illustrative enough to get you guys going again capibara aspect it's uh it's
01:17:32.560
now second nature in the Ruby community in capibara uh the velocity of getting
01:17:39.440
things done with capibara versus using cucumber at least for me it's tenfold uh I feel that I can express my test in the
01:17:46.120
language that I use every day and I'm still being able to do bdd outside in
01:17:51.480
testing in an efficient way uh in testing only the stuff that matter matters
01:18:00.800
questions all right thank you very much
01:18:23.760
guys
01:18:37.960
ah