RailsConf 2013

TDD Workshop: Mocking, Stubbing, and Faking External Services

By Harlow Ward & Adarsh Pandit

Help us caption & translate this video!

http://amara.org/v/FGao/

RailsConf 2013

00:00:16.400 you guys feeling good
00:00:18.640 soaking it in i know it's a lot um
00:00:22.320 as i mentioned to some of them some of
00:00:24.400 the people here
00:00:25.519 we had planned about seven modules and
00:00:28.480 we're through one so a lot of it will be
00:00:30.160 available as a markdown document
00:00:32.079 with step-by-step steps on the railsconf
00:00:34.960 tutorials
00:00:35.920 site so fear not and we're around all
00:00:38.320 week to answer
00:00:39.360 fun tdd questions we're both
00:00:42.960 relative newcomers to ruby and rails so
00:00:46.160 we empathize and have a good sense for
00:00:48.800 how
00:00:50.079 beginners get going so why don't i uh
00:00:53.360 throw a test in here
00:00:54.640 sounds good and then i'll let you make a
00:00:57.360 pass
00:00:58.239 so one of the questions we had uh just
00:01:00.399 before the
00:01:01.600 break there was how about kind of the
00:01:03.600 sad path right like how do we
00:01:05.439 how are we going to test that
00:01:08.240 validations occur and things of that
00:01:10.080 nature
00:01:11.040 so instead of doing an integration test
00:01:13.360 we're going to use a
00:01:15.040 library called shoulda matchers which is
00:01:18.080 a dsl
00:01:19.280 that can be used in our spec and dsl be
00:01:21.360 in a domain specific language
00:01:23.840 and that'll allow us to write
00:01:27.280 unit tests on these models to make sure
00:01:30.799 that
00:01:32.479 the validations and whatnot are present
00:01:37.680 so this is in the spirit of letting our
00:01:39.759 tests
00:01:42.159 assert the code we wish we had in our
00:01:43.520 code base so we won't add the
00:01:45.520 validation to the model until we have a
00:01:47.680 failing test that says that we need it
00:01:51.360 yeah and so just to describe what i've
00:01:53.759 done here
00:01:54.799 this file is spec models
00:01:57.840 task underscore spec dot rb so that's
00:02:01.680 some of the convention over
00:02:02.880 configuration so the spec for the
00:02:05.360 model should be in the models directory
00:02:07.520 and should have the same name
00:02:09.599 just with underscore spec appended to it
00:02:13.120 and what i've done here is this is
00:02:14.959 classic r spec
00:02:17.200 syntax i've described the task so we're
00:02:20.000 pointing to
00:02:21.200 this model and i'm using shoulda
00:02:23.200 matchers and saying it should validate
00:02:25.120 the presence
00:02:25.920 of the name does that look right
00:02:29.520 that looks good to me so let's get see
00:02:31.760 if this fails
00:02:32.959 so r spec what was the flag you're using
00:02:35.519 fd
00:02:37.599 uh spec models task spec rb
00:02:48.879 great so this error tells us
00:02:52.879 at the line that we added
00:02:56.400 that should a mattress runs a test where
00:02:59.120 it tries to
00:03:00.159 create this element without um
00:03:04.080 with something that's blank with a blank
00:03:05.920 element so the error says
00:03:08.319 um did not expect errors to include
00:03:10.319 can't be blank when the name is set to
00:03:12.400 nil and got the error
00:03:13.920 so this is what we wanted and what's
00:03:15.599 happening in the background here is
00:03:17.760 we're setting up the the model we're
00:03:20.959 calling
00:03:21.599 valid question mark on it and then
00:03:24.239 checking
00:03:24.879 the errors array for that model and
00:03:27.200 looking for
00:03:28.159 campy blank which is kind of the
00:03:29.360 standard output you'd see on a web form
00:03:31.840 next to that particular field
00:03:34.000 so instead of actually going into our
00:03:35.760 integration tests now
00:03:37.200 and checking the contents of the page
00:03:40.159 we're unit testing the model to make
00:03:41.760 sure that this validation is present
00:03:44.879 and that'll allow us to kind of not test
00:03:47.040 rails
00:03:48.319 yeah when we know
00:03:51.360 you know rails will issue
00:03:54.480 news bulletins when rails is not working
00:03:56.799 so we do our best not to test it
00:04:05.680 so since our test was for validation
00:04:09.680 and failed nicely in the way that we
00:04:11.760 wanted
00:04:12.799 harlow's adding a validation to the
00:04:16.400 model
00:04:18.400 to assert that the name the task name
00:04:22.000 exists and he got the test to pass so
00:04:25.040 could we just see the model again real
00:04:26.560 quick
00:04:27.040 yes so what that looks like is this so
00:04:29.840 within clatt
00:04:30.560 and this again the file here is app
00:04:33.440 models
00:04:34.280 task.rb
00:04:38.160 thanks yeah this is a great split so at
00:04:40.000 the top is the
00:04:41.440 model at the bottom is the test so
00:04:44.320 validates name
00:04:45.440 presence true and that leads for a nice
00:04:49.360 documentation later
00:04:51.360 that if someone's wondering what
00:04:53.680 validations are happening on a model
00:04:56.160 they can look at the unit tests from the
00:04:58.720 spec
00:05:00.080 and it'll show in plain english yeah
00:05:02.560 what's been set up so far
00:05:03.840 do you mind flipping that back to the
00:05:05.120 code absolutely one other point i wanted
00:05:07.440 to make here is
00:05:09.039 a question we get a lot from folks that
00:05:10.960 are new is
00:05:12.479 there are two layers of validation in
00:05:15.280 rails
00:05:16.160 there are what we have here which is
00:05:17.520 model level validations and you can add
00:05:19.680 database level validations as well
00:05:21.919 so when you run your migration you can
00:05:23.680 do something very similar
00:05:25.680 and say it needs to be present or the
00:05:28.000 database will
00:05:28.960 barf all over whatever you're trying to
00:05:30.479 do some ask
00:05:32.800 us if one is better than the other if
00:05:35.039 you prefer one or the other
00:05:37.440 and typically we'll do both so there's a
00:05:40.080 reason for that
00:05:40.880 the when you create
00:05:44.960 so the model level validations are sorry
00:05:47.840 the
00:05:48.160 database level validations are
00:05:50.080 impermeable you can't skip past them in
00:05:52.240 any way
00:05:53.120 there are ways in which you can get past
00:05:55.919 some of the model level
00:05:57.039 validations so we like to have both
00:06:00.080 and make sure that our data is clean
00:06:03.520 um so should a matchers has a bunch of
00:06:05.919 assertions that we can make
00:06:07.600 i just added another one which is
00:06:09.120 validates uniqueness of name
00:06:12.160 and then i run that assertion that fails
00:06:14.560 and then i can add that
00:06:17.680 up into my
00:06:25.120 multiple assertions so the question is
00:06:27.199 can you pass a block with multiple
00:06:28.960 validations and you can so there's two
00:06:31.759 ways to do this
00:06:33.759 let's get this passing and then i'll yep
00:06:36.000 so this passes really nicely
00:06:39.120 so what we did here was we asserted two
00:06:41.520 validations
00:06:42.639 within one line within the model on line
00:06:45.039 two
00:06:45.840 we said validates name presence true
00:06:48.479 uniqueness true
00:06:49.840 the other way that we could do this is
00:06:51.120 to split those out into two lines
00:06:53.440 um and just do that twice do you mind
00:06:56.240 just
00:06:56.560 demonstrating that real quick
00:07:00.400 so sorry what do you want to do here so
00:07:02.319 just uh
00:07:03.520 have two about one validation per line
00:07:06.000 oh okay
00:07:08.319 in the model
00:07:15.199 like two describes oh no i mean in the
00:07:17.360 model
00:07:19.280 oh i see gotcha just split that line to
00:07:23.199 the top pane
00:07:38.639 oops the users may be
00:07:42.400 familiar with the colon w's showing up
00:07:44.400 all over
00:07:51.280 yep and this passes nicely so i actually
00:07:53.360 prefer this syntax just because
00:07:56.240 it's a little easier to read but as our
00:07:58.479 participant asked us yes you can
00:08:00.560 for one element you can add all of the
00:08:02.720 assertions in one line
00:08:04.560 but to me each one is an independent
00:08:06.160 idea and i like how it maps to two
00:08:08.720 different
00:08:09.599 matches in the test file so two things
00:08:12.479 here
00:08:13.360 and two things there this was a quick
00:08:16.639 one
00:08:18.560 validations are pretty simple and we can
00:08:20.400 get more excited with them
00:08:22.720 as we go on but let's stop there and
00:08:25.919 let's have some questions
00:08:38.839 yes
00:08:52.399 every time
00:08:57.120 right so the question was um this can
00:09:00.399 begin to look like we're testing that
00:09:02.080 rails is doing
00:09:03.360 we're testing that rails is doing its
00:09:05.120 job properly
00:09:06.640 which is a great point i think the way
00:09:08.640 that i see this is that
00:09:09.920 is less that the validation is working
00:09:13.279 the way that it should that rails is
00:09:14.959 making it work and to me this asserts
00:09:17.440 that the validation exists
00:09:20.160 so this is a this is a
00:09:23.440 a constraint that i'm putting on the
00:09:24.800 model and as somebody else
00:09:27.120 starts going through and monkeying with
00:09:28.640 validations like let's say if i
00:09:30.800 add validates name
00:09:34.399 length must be minimum 20 characters
00:09:37.760 if in the process of that i'm drinking a
00:09:39.680 lot of coffee because i live in san
00:09:41.120 francisco and i've had pour overs all
00:09:42.560 day
00:09:43.839 i delete one of these and then i run my
00:09:45.839 test suite it's going to fail
00:09:49.040 so that's why we would add assertions
00:09:52.320 for these kinds of validations but it's
00:09:54.800 a great question
00:10:00.399 so the question is do we really test all
00:10:02.000 the validations all the time and the
00:10:03.360 answer is yes
00:10:04.880 and for that reason so if somebody
00:10:06.560 accidentally deletes one or changes it
00:10:08.560 then the test will fail and tell us yes
00:10:14.560 so the question was what about custom
00:10:16.320 validations so
00:10:17.760 custom validations are
00:10:20.800 a slightly more advanced topic what that
00:10:22.959 does essentially
00:10:24.160 is you can pass a method name to a
00:10:26.880 validation
00:10:27.920 so let's say rails gives us a bunch of
00:10:31.040 these canned
00:10:32.000 validations that it exists that it's
00:10:35.120 a number that it's at least this long
00:10:37.279 and so forth
00:10:38.320 if we wanted to make sure that every
00:10:41.360 task had
00:10:42.320 the word kitten in it so we could we
00:10:44.880 would write
00:10:45.839 validates and then we would pass a
00:10:48.240 method name and the method name might be
00:10:50.720 checks it is a kitten oriented task or
00:10:53.519 something
00:10:54.399 and then we would have a method that
00:10:56.800 would be called
00:10:57.760 checks kitten oriented task and that
00:10:59.920 would assert
00:11:01.920 that the task name would contain the
00:11:04.000 word kitten and would
00:11:05.279 return a true false and you would have a
00:11:08.320 test for that as well
00:11:09.519 and there's a there's a convention in
00:11:11.920 rails
00:11:12.640 so if you have validate let's say email
00:11:15.200 as a field for example
00:11:17.680 you could go email true and then
00:11:20.959 this will expect that a file lives in
00:11:24.000 app validators
00:11:27.360 email validator
00:11:30.640 and we would write unit tests unit tests
00:11:33.519 for that validator
00:11:35.680 in spec validators to make sure that we
00:11:38.560 can test the positive and negative cases
00:11:40.399 of what a
00:11:41.440 valid email looks like i wrote one of
00:11:44.480 these recently i can absolutely put an
00:11:46.240 example of that up onto the railsconf
00:11:48.480 tutorial website tonight too i think
00:11:50.000 it's super interesting testing your
00:11:51.519 custom validators
00:11:54.000 so we'll get some example code for that
00:11:55.279 up too yep and the test would live in
00:11:58.240 spec validators email validator spec
00:12:03.040 so convention yes
00:12:13.200 nothing so the question is the reason
00:12:16.560 for this is to
00:12:17.760 alert to have the test fail if some
00:12:19.440 developer accidentally removes the
00:12:21.440 validation
00:12:22.959 but what's to stop another developer
00:12:25.040 from removing both
00:12:26.560 the validation and the test for it and
00:12:28.800 the answer is
00:12:29.839 nothing well the answer is not really
00:12:32.480 nothing
00:12:32.959 the things that prevent you from being
00:12:34.480 able to do that are
00:12:36.000 the fact that you're programming as a
00:12:37.839 pair the fact that you have
00:12:39.920 uh that you give your own code a good
00:12:41.920 once over beforehand
00:12:44.240 and that you do code review as a team
00:12:48.560 of course if anybody wants to make any
00:12:50.000 change you can jam it into master and
00:12:52.320 there's nothing to prevent it but we try
00:12:55.040 and create
00:12:56.399 checks sort of qc level checks along the
00:12:59.200 way before things get merged into master
00:13:01.920 including really rigorous code review
00:13:03.440 and that's i think where we would try
00:13:04.560 and catch that but of course things do
00:13:07.120 sneak past good question
00:13:13.200 other questions
00:13:18.480 so we have five minutes left uh i think
00:13:20.720 that might not be enough time to get
00:13:22.079 going on the next
00:13:23.600 module okay what do you think um i think
00:13:26.959 that's right so why don't we uh when we
00:13:28.240 break a few minutes early
00:13:29.600 um we'll be walking around if we want to
00:13:31.760 answer any more questions
00:13:33.200 anymore
00:13:38.240 i know so we have an announcement one
00:13:41.279 second
00:13:42.560 coupon codes for 20 of everything on
00:13:46.639 learn
00:13:49.600 great so chad informs me that we have a
00:13:52.639 coupon code that
00:13:53.920 we use on our learn portal
00:14:02.320 code um and that's good for 20 off
00:14:05.600 everything in the learn portal including
00:14:09.199 our subscription servers our
00:14:11.839 subscription service learn prime
00:14:13.440 uh it's uh one month for free
00:14:17.920 20 off the first month sorry and with uh
00:14:20.639 with learn prime we have a series of uh
00:14:23.120 ruby on rails workshops that are
00:14:24.959 recorded
00:14:26.160 we've written uh ebooks on backbone.js
00:14:29.920 we have an ebook called ruby science
00:14:31.440 which is under development right now
00:14:33.680 and that really digs into some of these
00:14:35.199 patterns we're talking about in a rails
00:14:36.800 application
00:14:39.120 so we have a great culture around kind
00:14:41.120 of continued
00:14:42.240 growth and development of thoughtbot and
00:14:43.839 this is something that that all of us
00:14:45.600 are putting time into
00:14:47.440 um our regulators harlow's working on
00:14:50.560 ruby science and i'm working on our
00:14:52.240 new version of our playbook online
00:15:06.079 over the course of four weeks so we'll
00:15:09.120 break now
00:15:10.160 and i just wanted to say thanks for
00:15:11.680 everybody coming in here i think it's
00:15:13.600 doing tdd is really difficult and it
00:15:15.360 takes a lot of hard work
00:15:16.959 and pairing and i'm glad to see
00:15:18.480 everybody got together and helped each
00:15:20.399 other out
00:15:20.959 so that was awesome made my day and
00:15:23.839 thanks again for everybody
00:15:25.120 for coming out we're around all week if
00:15:27.279 you have questions pull any of us aside
00:15:29.040 with robots on our shirts
00:15:31.680 and we'll happy to answer questions and
00:15:34.079 thanks for coming
00:16:10.000 you