RailsConf 2013

BDD and Acceptance Testing with RSpec & Capybara

By Brian Sam-Bodden

Behavior-Driven Development and Acceptance Testing are heavily intertwined and in many aspects are one and the same. Both focus on starting at the outer layers of your application by concentrating on what matter to users; behavior. In this session/workshop we'll talk about how testing can be used both for specifying your application yet to be develop expected behavior and as accurate, running documentation that can be used to validate your stakeholder's acceptance criteria. We'll talk about the different types of testing and do a few hands-on exercises to flesh out a Rails application with RSpec and Capybara.

Help us caption & translate this video!

http://amara.org/v/FGa3/

RailsConf 2013

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