< Return to Video

RailsConf 2014 - Effectively Testing Services by Neal Kemp

  • 0:18 - 0:20
    NEAL KEMP: Hi RailsConf.
  • 0:20 - 0:21
    Today we're going to be talking about
  • 0:21 - 0:23
    testing your services.
  • 0:23 - 0:24
    But before we get into that,
  • 0:24 - 0:26
    I want to introduce myself.
  • 0:26 - 0:29
    My name's Neal. I'm originally from Iowa,
  • 0:29 - 0:32
    so I feel at home here in the Midwest.
  • 0:32 - 0:35
    Now I live in California, in LA specifically,
  • 0:35 - 0:37
    and I'm a software developer and
  • 0:37 - 0:40
    independent consultant who does Rails,
  • 0:40 - 0:42
    JavaScript, HTML, CSS.
  • 0:42 - 0:43
    Basically if you name an acronym
  • 0:43 - 0:46
    I've probably coded in it at some point.
  • 0:46 - 0:50
    So, today's talk is going to be the what,
  • 0:50 - 0:55
    the why, and the how of testing your services.
  • 0:55 - 0:58
    This is not a talk about building testable
    services.
  • 0:58 - 1:00
    I could do an entire talk about that on
  • 1:00 - 1:04
    its own. It's also not necessarily a talk
    about
  • 1:04 - 1:08
    test-driven development. While I'm a practitioner,
    I don't think
  • 1:08 - 1:13
    that the principles applied here correspond
    directly to test-driven
  • 1:13 - 1:15
    or not test-driven development.
  • 1:15 - 1:16
    [laughter]
  • 1:16 - 1:22
    So. Got that one. Good.
  • 1:22 - 1:24
    So first we're gonna talk about the what.
    So,
  • 1:24 - 1:26
    we have to ask ourselves, what is a service.
  • 1:26 - 1:29
    So I break it down into two main categories.
  • 1:29 - 1:32
    First of all we have external services, like
    the
  • 1:32 - 1:38
    Twitter API, Facebook's API, or Amazon Web
    Services. And
  • 1:38 - 1:42
    the other category is internal software-oriented
    architecture, a buzz
  • 1:42 - 1:44
    word we all know and love.
  • 1:44 - 1:48
    So, basically for the purpose of this talk,
    it
  • 1:48 - 1:53
    means anytime you're making an HTTP request
    to an
  • 1:53 - 1:57
    endpoint in another repository. So, basically
    any network request
  • 1:57 - 2:01
    you're making outside of your application.
  • 2:01 - 2:04
    So now we're gonna talk about. Cause we need
  • 2:04 - 2:07
    some justification before we go ahead and
    test all
  • 2:07 - 2:11
    of our services without question. So, first
    we have
  • 2:11 - 2:14
    to ask ourselves, why are services themselves
    important? I
  • 2:14 - 2:16
    think a lot of these are pretty self-evident.
    It
  • 2:16 - 2:19
    allows us to build things faster. It allows
    us
  • 2:19 - 2:22
    to scale more easily. And we use them on
  • 2:22 - 2:25
    basically every application. I don't think
    I can personally
  • 2:25 - 2:28
    think of an app I've built in the past
  • 2:28 - 2:31
    few years that hasn't glued on multiple services.
  • 2:31 - 2:33
    And I'm also noticing that we're using more
    and
  • 2:33 - 2:38
    more services for every application. So I
    would argue
  • 2:38 - 2:42
    that services are critical to modern Rails
    development. So
  • 2:42 - 2:44
    we have to ask ourselves then, why is testing
  • 2:44 - 2:48
    those services important? Well, first of all,
    you should
  • 2:48 - 2:50
    be testing everything else, so why would it
    be
  • 2:50 - 2:55
    different for services? And services often
    compose critical features
  • 2:55 - 2:59
    of your application. For example, a stripe
    integration. If
  • 2:59 - 3:00
    your billing's down, you're gonna have a lot
    of
  • 3:00 - 3:04
    issues. You know, if you have an API request
  • 3:04 - 3:07
    to S3, you're not gonna be able to serve
  • 3:07 - 3:09
    images, if that's down.
  • 3:09 - 3:11
    And you might also encounter problems with
    these APIs.
  • 3:11 - 3:15
    I know I sure have. Basically, any time I've
  • 3:15 - 3:19
    worked with an API there's been some unexpected
    results.
  • 3:19 - 3:21
    So the first example I'm gonna take you through
  • 3:21 - 3:24
    is, you know, an internal API built by consultants
  • 3:24 - 3:26
    in another part of the company. So this is
  • 3:26 - 3:30
    the software-oriented architecture we're talking
    about. And they were
  • 3:30 - 3:34
    exposing this API for our Rails app to consume,
  • 3:34 - 3:37
    but we had issues all along the way, and
  • 3:37 - 3:41
    it served to increase the project length significantly.
    Sometimes
  • 3:41 - 3:44
    we'd have random null responses when we were
    supposed
  • 3:44 - 3:48
    to get objects. There is random inconsistencies
    where we'd
  • 3:48 - 3:52
    get weird symbols being printed out and different
    formatting.
  • 3:52 - 3:55
    And in general it was a catastrophe.
  • 3:55 - 3:58
    So it definitely lengthened the time to completion.
    And
  • 3:58 - 4:01
    this was a lot due to a failure on
  • 4:01 - 4:04
    our part to, you know, test the API thoroughly.
  • 4:04 - 4:06
    So we couldn't express to them, you know,
    the
  • 4:06 - 4:08
    problems we were having until we put it into
  • 4:08 - 4:10
    production. So this is one problem that could
    have
  • 4:10 - 4:13
    been solved by testing first.
  • 4:13 - 4:16
    So, now we're gonna talk about a few problems
  • 4:16 - 4:18
    I've had with external APIs. And I'm sure
    all
  • 4:18 - 4:22
    of you have encountered similar issues with
    APIs in
  • 4:22 - 4:23
    the past.
  • 4:23 - 4:26
    So do we have any NHL fans in the,
  • 4:26 - 4:28
    in the house here? Yeah? Chicago Black Hawks.
    Doing
  • 4:28 - 4:31
    pretty well in the play-offs so far. We'll
    see
  • 4:31 - 4:33
    how they go. I mean, obviously they're gonna
    get
  • 4:33 - 4:36
    crushed by the Kings in a few rounds here,
  • 4:36 - 4:39
    or the Sharks, possibly. But we'll see. I
    don't
  • 4:39 - 4:41
    want to start a sports rivalry today.
  • 4:41 - 4:46
    So you know, this basically ranged from small
    annoyances
  • 4:46 - 4:50
    to, you know, major issues with this API.
    So
  • 4:50 - 4:53
    we'd have annoyances like this, where some
    responses would
  • 4:53 - 4:55
    come back with an id for the team, and
  • 4:55 - 4:57
    others would come back with a code. And in
  • 4:57 - 5:00
    this case, both of them refer to Anaheim.
    So
  • 5:00 - 5:01
    this is a minor annoyance. You can code around
  • 5:01 - 5:02
    that.
  • 5:02 - 5:06
    Here, we have an undocumented bug, where basically
    the
  • 5:06 - 5:08
    goals were all supposed to be as a part
  • 5:08 - 5:10
    of an array, but if you only had one
  • 5:10 - 5:12
    goal, it would be an object. And sadly we
  • 5:12 - 5:16
    discovered this one in production, during
    a game. So
  • 5:16 - 5:18
    that wasn't ideal.
  • 5:18 - 5:21
    But, worst of all, after we had gone through
  • 5:21 - 5:24
    all of the trouble of fixing these, we realized
  • 5:24 - 5:27
    that there was no versioning on this API.
    So,
  • 5:27 - 5:30
    even if we fixed it, we might be fixing
  • 5:30 - 5:35
    it again a week later. So this is basically
  • 5:35 - 5:39
    what it felt like to work with their API.
  • 5:39 - 5:42
    So, another project I worked on, this is just
  • 5:42 - 5:44
    kind of a fun side project, was a Snapchat
  • 5:44 - 5:48
    API Client, so I could, you know, work with
  • 5:48 - 5:52
    the Snapchat private API. And, well, one of
    these
  • 5:52 - 5:56
    examples is extreme, in that there is haphazard
    documentation,
  • 5:56 - 5:59
    or no documentation, in this case. I think
    we've
  • 5:59 - 6:04
    all worked with APIs that have improper documentation.
  • 6:04 - 6:05
    But in this case we didn't even know what
  • 6:05 - 6:07
    the requests were, so we had to figure that
  • 6:07 - 6:11
    out. There's also bizarre obfuscation implanted
    inside of the
  • 6:11 - 6:16
    app itself that basically encrypted, on their
    iPhone, so
  • 6:16 - 6:19
    people like me couldn't go in and build things
  • 6:19 - 6:21
    like this. And there's a GitHub link if you're
  • 6:21 - 6:22
    curious.
  • 6:22 - 6:26
    So, now that we've talked a little bit about
  • 6:26 - 6:29
    why it's important and outlined some of the
    problems
  • 6:29 - 6:31
    you might encounter, we're gonna talk about
    how you're
  • 6:31 - 6:36
    actually going to test these.
  • 6:36 - 6:38
    So first we need to ask ourselves, what is
  • 6:38 - 6:43
    different about services than regular code
    that we're testing?
  • 6:43 - 6:47
    Well, first of all, we have external network
    requests
  • 6:47 - 6:50
    that are being made, and second of all, you
  • 6:50 - 6:52
    don't own the code, so you can't really do
  • 6:52 - 6:54
    unit testing on it. It all has to be
  • 6:54 - 6:57
    done from integration test perspective.
  • 6:57 - 7:02
    So, what I propose for your tests, in general,
  • 7:02 - 7:06
    is that you turn Airplane Mode on. This, I
  • 7:06 - 7:08
    find, is the best way to think about your
  • 7:08 - 7:12
    tests, because, first of all, failure is really
    bad
  • 7:12 - 7:15
    in testing, and you shouldn't be making any,
    any
  • 7:15 - 7:17
    network requests.
  • 7:17 - 7:19
    So I think of this kind of in two
  • 7:19 - 7:21
    ways. First of all, so it's Airplane Mode
    in
  • 7:21 - 7:23
    the test mode so you can't do these things.
  • 7:23 - 7:25
    But also it should be a test that you
  • 7:25 - 7:28
    can run on an airplane. Basically meaning
    that if
  • 7:28 - 7:31
    you're, you know, on a long trans-Atlantic
    flight or
  • 7:31 - 7:33
    in the RailsConf lobby, you can still make
    your
  • 7:33 - 7:40
    tests and, and they won't fail because of
    network
  • 7:40 - 7:42
    issues.
  • 7:42 - 7:45
    So this means you should not interact with
    your
  • 7:45 - 7:49
    services from your testing environment. And
    we have a
  • 7:49 - 7:53
    few caveats which I'll get into now. So, this
  • 7:53 - 7:57
    includes dummy APIs. So there's some API makers
    that
  • 7:57 - 7:59
    have their real API, and then they have a
  • 7:59 - 8:03
    fake API which you can hit with requests,
    but
  • 8:03 - 8:06
    it doesn't make any changes to your data.
  • 8:06 - 8:08
    So you can't hit those, because those are
    somewhere
  • 8:08 - 8:11
    else on the network. But I do allow you
  • 8:11 - 8:16
    to make pre-recorded responses to those end
    points, and
  • 8:16 - 8:18
    that means you can record them within your
    test
  • 8:18 - 8:20
    suite, which we'll get into in a bit more
  • 8:20 - 8:22
    detail later.
  • 8:22 - 8:25
    So, for these examples, I'm going to be assuming
  • 8:25 - 8:29
    that you're using Rails, obviously, and that
    you're using
  • 8:29 - 8:35
    rspec for simplicities sake. So, it's time
    to stub
  • 8:35 - 8:37
    out these requests.
  • 8:37 - 8:41
    So, when you're stubbing an object, you're
    basically -
  • 8:41 - 8:43
    for those who don't know - it's basically
    putting
  • 8:43 - 8:45
    like a fake object in front of that object,
  • 8:45 - 8:48
    so you're hitting that object instead of hitting
    the
  • 8:48 - 8:50
    real one and, you know, saving time with,
    like
  • 8:50 - 8:54
    setup processes and stuff like that. And we're
    doing
  • 8:54 - 8:56
    a similar thing when you're stubbing a request
    to
  • 8:56 - 8:59
    an endpoint, except we're saving a lot more
    time
  • 8:59 - 9:01
    when we're doing so, because we don't have
    to
  • 9:01 - 9:04
    make that additional network request.
  • 9:04 - 9:08
    So there's some libraries that include built-in
    stubbing. So
  • 9:08 - 9:13
    Typhoeus, if I pronounced that correctly,
    Faraday and Excon
  • 9:13 - 9:18
    are three examples of pretty widely-used HTTP
    libraries built
  • 9:18 - 9:21
    on top of net HTTP, I think, that have
  • 9:21 - 9:24
    built-in stubbing functionality.
  • 9:24 - 9:27
    But we can simplify this a little bit and
  • 9:27 - 9:29
    use something called webmock, which I'm sure
    many of
  • 9:29 - 9:32
    you have worked with in the past, which is
  • 9:32 - 9:36
    a general purpose stubbing library for your
    test suite,
  • 9:36 - 9:40
    so you don't have to learn each individual
    library's
  • 9:40 - 9:43
    stubbing methods.
  • 9:43 - 9:45
    So I'll take you through a quick example.
    Here
  • 9:45 - 9:49
    is basic spec_helper. Nothing really interesting
    about this, except
  • 9:49 - 9:52
    you have to include disable_net_connect! at
    the bottom. The
  • 9:52 - 9:57
    rest is boilerplate. So I've highlighted that.
    And, obviously,
  • 9:57 - 9:59
    with all of these examples, you should be
    putting
  • 9:59 - 10:02
    the gem in your gem file and bundle installing
  • 10:02 - 10:04
    before you start.
  • 10:04 - 10:07
    So, when you put this in your code for
  • 10:07 - 10:10
    the first time, you'll get a really great
    error
  • 10:10 - 10:12
    with this, and I really like getting these
    errors,
  • 10:12 - 10:14
    because it tells me exactly, in my code, where
  • 10:14 - 10:17
    I'm making network requests. So if you're
    not already
  • 10:17 - 10:22
    doing airplane mode tests, you should just
    plug this
  • 10:22 - 10:26
    disable_net_connect! in, and then you'll get
    this error, which
  • 10:26 - 10:29
    will tell you where you're making these network
    requests.
  • 10:29 - 10:31
    And it also is really handy, and it gives
  • 10:31 - 10:34
    you, actually, the request you're making at
    the bottom.
  • 10:34 - 10:38
    So you can copy and paste that into your
  • 10:38 - 10:41
    test in order to stub it automatically. And
    obviously
  • 10:41 - 10:43
    you'll have to collect the body and the headers
  • 10:43 - 10:47
    yourself, if you need to use those as well.
  • 10:47 - 10:52
    So, for the following examples, we're gonna
    use probably
  • 10:52 - 10:58
    the most, sorry, most simple FacebookWrapper
    ever invented. Basically,
  • 10:58 - 11:01
    all we're doing here is sending a GET request
  • 11:01 - 11:06
    to Facebook graph, the public API, for a user.
  • 11:06 - 11:08
    And what this does is it just returns, like,
  • 11:08 - 11:11
    very basic Facebook information about you.
    It has your
  • 11:11 - 11:15
    Facebook username, your name, and an id and
    a
  • 11:15 - 11:17
    few other fields.
  • 11:17 - 11:19
    And then what we're doing with user_id up
    at
  • 11:19 - 11:23
    the top is we are just pulling out the
  • 11:23 - 11:27
    value for key_id. So this, all it does is
  • 11:27 - 11:33
    return your Facebook id. Super, super simple.
    And make
  • 11:33 - 11:35
    sure, since we're putting it in lib, that
    you
  • 11:35 - 11:38
    require it at some point in your loading.
  • 11:38 - 11:41
    So now we're gonna look at a test for
  • 11:41 - 11:43
    this. So this is a test where we're not
  • 11:43 - 11:45
    making a network request, but we're stubbing
    it out
  • 11:45 - 11:49
    with webmock. So, at the bottom, you can see
  • 11:49 - 11:53
    we're doing our testing case, and we're setting
    up
  • 11:53 - 11:58
    an expectation that our user_id is equal to
    Arjun's
  • 11:58 - 12:01
    user_id. And I'm using Arjun because he was
    the
  • 12:01 - 12:04
    maker of the Facebook graph API wrapper.
  • 12:04 - 12:07
    And, you can see, now, above, we are stubbing
  • 12:07 - 12:10
    the request, just like you'd stub an object.
    We're
  • 12:10 - 12:13
    stubbing the method of the HTTP request and
    then
  • 12:13 - 12:18
    we're send, putting the link as the second
    argument.
  • 12:18 - 12:23
    Next, we have to set up what it returns,
  • 12:23 - 12:27
    and this is just an HTTP response that we're
  • 12:27 - 12:29
    returning. So we want to put a status.
  • 12:29 - 12:33
    You can set headers, which I generally don't
    do,
  • 12:33 - 12:35
    but if you're doing any operations with the
    headers,
  • 12:35 - 12:41
    you should definitely set up these in your
    responses.
  • 12:41 - 12:44
    And the body, we have a really simple JSON
  • 12:44 - 12:47
    string. I've cut out a few fields for brevity.
  • 12:47 - 12:49
    But you can see it has an id, a
  • 12:49 - 12:51
    first_name, and a username.
  • 12:51 - 12:55
    So, this test will pass, and we're also making
  • 12:55 - 12:58
    no net requests, work requests. So, the reasons
    it's
  • 12:58 - 13:02
    better is it, first of all, it's faster, and
  • 13:02 - 13:04
    we also aren't getting this intermittent failure
    that we
  • 13:04 - 13:09
    were talking about earlier from the network
    request.
  • 13:09 - 13:13
    So, that's a good general way, but there's
    ways
  • 13:13 - 13:15
    we can also save time with this. So a
  • 13:15 - 13:19
    lot of the really popular libraries for API
    wrappers
  • 13:19 - 13:24
    also include mock-services within themselves
    or as an additional
  • 13:24 - 13:27
    library on the side, and they use that for,
  • 13:27 - 13:30
    you know, internal testing with their gems.
    So I
  • 13:30 - 13:32
    recommend, if, if you can find one, to use
  • 13:32 - 13:35
    this before you can go and use webmock, because
  • 13:35 - 13:36
    it'll save you a lot of time.
  • 13:36 - 13:39
    And I'll take you through a quick example.
    So
  • 13:39 - 13:45
    we're gonna use Facebook graph mock here.
    And all
  • 13:45 - 13:48
    we are doing is putting it into spec_helper.
    We're
  • 13:48 - 13:53
    just including the methods and requiring it.
    Pretty straightforward.
  • 13:53 - 13:56
    And now we're gonna look at a spec.
  • 13:56 - 14:01
    So, basically, all we're doing is we're wrapping
    the
  • 14:01 - 14:05
    test case within a wrapper that mocks out
    the
  • 14:05 - 14:08
    request. So basically, all this one's doing
    is saying
  • 14:08 - 14:11
    we're sending a git request to Facebook graph
    back
  • 14:11 - 14:15
    slash Arjun, and then the third argument,
    in this
  • 14:15 - 14:20
    case, is users/arjun_public, which is where
    the JSON file
  • 14:20 - 14:23
    of this response is located in the gem.
  • 14:23 - 14:27
    So, you can also specify your own responses,
    and
  • 14:27 - 14:30
    I'd recommend you do that, because I found,
    actually,
  • 14:30 - 14:34
    some issues with the Facebook graph mock mocking,
    like,
  • 14:34 - 14:39
    responses, have some outdatedness in them.
  • 14:39 - 14:42
    So, but this, you know, example, I'm not gonna
  • 14:42 - 14:44
    take you through all of the gems that have
  • 14:44 - 14:46
    this. But this can go to show that there
  • 14:46 - 14:50
    are some benefits that you get from using
    this.
  • 14:50 - 14:52
    It's already stubbed for you. You don't have
    to
  • 14:52 - 14:56
    learn the API endpoints in order to use it,
  • 14:56 - 14:59
    and some of these provide prerecorded responses
    for your
  • 14:59 - 15:01
    use, so you don't have to go out and
  • 15:01 - 15:03
    collect these. So it's just a good way of
  • 15:03 - 15:07
    saving time, if you're using some popular
    libraries.
  • 15:07 - 15:11
    Next, I'm going to take you through sham_rack,
    which
  • 15:11 - 15:14
    is one of my more favorite ways of doing
  • 15:14 - 15:16
    this. I kind of find this to be a
  • 15:16 - 15:20
    fun way. Basically what sham_rock does, sorry,
    sham_rack does
  • 15:20 - 15:24
    is it allows you to mount rack-based apps,
    which
  • 15:24 - 15:28
    include Rails and Sinatra and others, and
    it allows
  • 15:28 - 15:34
    you to make requests against these fake apps.
  • 15:34 - 15:37
    So, in this case, we're going to get a
  • 15:37 - 15:40
    little help from Sinatra in order to stub
    out
  • 15:40 - 15:46
    these endpoints. So, spec_helper, the only
    thing interesting is
  • 15:46 - 15:50
    that we leave in web-mock. Pretty boring there.
    But
  • 15:50 - 15:53
    then we get to our fake. So I usually
  • 15:53 - 15:57
    just put this spec/support and then fake whatever
    it
  • 15:57 - 15:59
    is, in this case fake_facebook.
  • 15:59 - 16:01
    And this just means it'll be loaded when you
  • 16:01 - 16:06
    run your specs automatically. But it won't
    be, obviously,
  • 16:06 - 16:09
    loaded into your production or staging environments,
    or development.
  • 16:09 - 16:12
    So, in this case, at the top we can
  • 16:12 - 16:15
    see, we're calling sham_rack, and we're setting
    up the
  • 16:15 - 16:17
    endpoint which we're hitting against, which
    in this case
  • 16:17 - 16:20
    is graph dot facebook dot com. And 433 is
  • 16:20 - 16:25
    just specifying that we're using the HTTPS
    SSL link,
  • 16:25 - 16:27
    and dot Sinatra just means we're going to
    be
  • 16:27 - 16:30
    passing it in a Sinatra app.
  • 16:30 - 16:34
    So, basically, contained within this block
    is a Sinatra
  • 16:34 - 16:36
    app, and you can do virtually anything you
    can
  • 16:36 - 16:38
    do with a regular Sinatra app, which is really
  • 16:38 - 16:41
    cool. So you can just, you're just basically
    mounting
  • 16:41 - 16:44
    this and testing against it.
  • 16:44 - 16:47
    So, for those of you who don't use Sinatra
  • 16:47 - 16:51
    very much, all we're doing here is specifying
    with
  • 16:51 - 16:54
    the GET keyword that we're making a GET request
  • 16:54 - 16:58
    to back slash something, and just like Rails,
    when
  • 16:58 - 17:01
    you rake routes you'll see the parametrization
    of things
  • 17:01 - 17:03
    with a colon before it. We're doing the exact
  • 17:03 - 17:05
    same thing here with username.
  • 17:05 - 17:08
    So, you'll see, in the middle, in the link
  • 17:08 - 17:11
    we interpolate params username, and that's
    how you pull
  • 17:11 - 17:14
    that out. So this is essentially just returning
    a
  • 17:14 - 17:18
    string that is this response. You can obviously
    spice
  • 17:18 - 17:21
    this up by setting status codes, adding conditionals
    in
  • 17:21 - 17:25
    here if you need some more dynamic power,
    and
  • 17:25 - 17:29
    also setting up the headers. And you can also,
  • 17:29 - 17:31
    which I sometimes do this in my testing, is
  • 17:31 - 17:34
    back it with like a small yml database, so
  • 17:34 - 17:36
    you can get some more realistic data than
    just
  • 17:36 - 17:40
    a simple string.
  • 17:40 - 17:46
    So, that's the response. And. Now, when we're
    writing
  • 17:46 - 17:52
    our spec for sham_rack, all we're doing is
    keeping
  • 17:52 - 17:54
    it on this base level. We don't have to
  • 17:54 - 17:57
    wrap it with anything, because it will automatically,
    in
  • 17:57 - 18:00
    your tests, pick up the fact that you have
  • 18:00 - 18:03
    sham_rack mounted, and it will automatically
    hit against that
  • 18:03 - 18:08
    endpoint rather than hitting against the network.
  • 18:08 - 18:13
    So, you might ask, why is this better? I
  • 18:13 - 18:15
    think there are a few reasons. First, I find
  • 18:15 - 18:18
    it more dynamic. I find it more expressive
    as
  • 18:18 - 18:20
    well, and you can really add, you know, as
  • 18:20 - 18:24
    much functionality you need to test your integrations
    as
  • 18:24 - 18:26
    you want. And you can also back it with
  • 18:26 - 18:29
    yml if you need, you know, some pre-population
    of,
  • 18:29 - 18:33
    you know, real data. And it's also more readable.
  • 18:33 - 18:35
    Let's go back to this for a second. And,
  • 18:35 - 18:37
    you can see, like, reading through this is
    a
  • 18:37 - 18:39
    lot easier to parse through, and you know
    where
  • 18:39 - 18:42
    the API requests are being made to, versus
    the
  • 18:42 - 18:45
    stubbing we showed in the first example, with
    web-mock,
  • 18:45 - 18:46
    is a little bit hard to read. So that's
  • 18:46 - 18:49
    why I prefer to use this.
  • 18:49 - 18:53
    So next, we're going to talk about vcr, which
  • 18:53 - 18:55
    is a pretty widely-used gem. And this one
    has
  • 18:55 - 18:58
    some other benefits that I think are really
    important
  • 18:58 - 19:03
    to use. Basically it prerecords your responses,
    and we'll
  • 19:03 - 19:05
    take you through an example.
  • 19:05 - 19:10
    So, spec_helper. The only thing interesting
    here. We have
  • 19:10 - 19:13
    the vcr configuration block, and all we're
    doing is
  • 19:13 - 19:19
    setting a cassette library. So that's basically
    where these
  • 19:19 - 19:21
    responses will be saved. And then we're hooking
    into
  • 19:21 - 19:24
    web-mock, because that's the stubbing library
    we're using.
  • 19:24 - 19:30
    So, here's a spec. And as you can see,
  • 19:30 - 19:34
    it's really, really similar to the Facebook
    graph mock.
  • 19:34 - 19:36
    So basically what this does is, you're wrapping
    it
  • 19:36 - 19:41
    in a block with vcr. So vcr, what it
  • 19:41 - 19:43
    does, is it goes out to the network and
  • 19:43 - 19:46
    makes the request for you, in your testing
    environment,
  • 19:46 - 19:49
    and it pulls that response back and saves
    it,
  • 19:49 - 19:53
    in this case, at Facebook user_arjun.
  • 19:53 - 19:54
    And the nice thing about this is you don't
  • 19:54 - 19:58
    have to go out and collect your own responses,
  • 19:58 - 20:00
    which I find to be pretty tedious and also
  • 20:00 - 20:03
    error prone. But, it also means you don't
    have
  • 20:03 - 20:08
    to break airplane mode with your tests, because
    you
  • 20:08 - 20:11
    can run this before, and you can cache all
  • 20:11 - 20:15
    of the JSON responses and play them back in
  • 20:15 - 20:18
    your build. So when you're running it on Travis
  • 20:18 - 20:20
    EI or Circle or whatever you happen to use,
  • 20:20 - 20:23
    you're not gonna break your build because
    of network
  • 20:23 - 20:28
    failure. You're going to be using these cached
    responses.
  • 20:28 - 20:31
    And that also just allows you to verify the
  • 20:31 - 20:34
    responses. So, like I mentioned, it's a little
    error
  • 20:34 - 20:36
    prone. I've tried collecting these responses
    on my own
  • 20:36 - 20:39
    and, you know, sometimes I copy and paste
    them
  • 20:39 - 20:42
    wrong and come up with an issue. So this
  • 20:42 - 20:44
    kind of allows you to, like, have a nice
  • 20:44 - 20:47
    programatic way of pulling those in.
  • 20:47 - 20:51
    So, there's also an additional build process
    you can
  • 20:51 - 20:55
    add. So, for the NHL example I talked about,
  • 20:55 - 20:57
    the problem was there was no versioning. So
    what
  • 20:57 - 21:00
    you can do is, if you want bonus points,
  • 21:00 - 21:03
    and you are really dependent on an API that
  • 21:03 - 21:05
    doesn't have versioning, you can do some kind
    of
  • 21:05 - 21:09
    build process or, you know, test setup, where
    you're
  • 21:09 - 21:11
    basically running it outside of your normal
    test mode,
  • 21:11 - 21:14
    and you check the casettes for diffs, and
    verify
  • 21:14 - 21:17
    that the responses are not changed from before.
    So
  • 21:17 - 21:19
    this can help you avoid versioning issues.
    So I
  • 21:19 - 21:24
    recommend that if you're using something like
    NHL API.
  • 21:24 - 21:27
    So, the next one we're gonna briefly talk
    about
  • 21:27 - 21:31
    is puffing-billy. And, aside from having a
    really cool
  • 21:31 - 21:35
    name and a nice logo on their GitHub, this
  • 21:35 - 21:38
    is an interesting gem to use. We're not gonna
  • 21:38 - 21:40
    use an example here, but basically what it
    is
  • 21:40 - 21:45
    is for in-browser requests. So basically if
    you're having
  • 21:45 - 21:50
    integrations that are browser-based, you can
    record and reuse.
  • 21:50 - 21:55
    Just like vcr, and use those responses again.
  • 21:55 - 21:59
    So, I don't want you guys to think that
  • 21:59 - 22:00
    all of this has to be done in Ruby,
  • 22:00 - 22:04
    and that you have to use vcr to first
  • 22:04 - 22:06
    record your responses. There's a lot of tools
    out
  • 22:06 - 22:11
    there that will help you to collect these
    responses,
  • 22:11 - 22:14
    test API endpoints faster, and I want to share
  • 22:14 - 22:17
    some of those with you.
  • 22:17 - 22:22
    So, Chrome Dev Tools. Has anyone heard of
    this
  • 22:22 - 22:25
    in here? Yeah. Probably, probably all of you.
    But
  • 22:25 - 22:26
    this is the first one I'm mentioning because
    I
  • 22:26 - 22:30
    use it, probably every day. Obviously it gives
    you
  • 22:30 - 22:33
    a really nice way of viewing responses and
    requests
  • 22:33 - 22:37
    and resending them. So super useful. I'm not
    gonna
  • 22:37 - 22:38
    get too far in-depth in that one because I'm
  • 22:38 - 22:41
    assuming most people have worked with it.
    But it
  • 22:41 - 22:42
    doesn't hurt to mention.
  • 22:42 - 22:46
    So next, Postman. If you want to stay within
  • 22:46 - 22:49
    Chrome. This is an extension you can use.
    And
  • 22:49 - 22:52
    it basically gives you a user interface around
    running
  • 22:52 - 22:55
    these requests so that you can have kind of
  • 22:55 - 22:58
    an easier way to play with re, requests and
  • 22:58 - 23:00
    responses. And it allows you save them. It
    gives
  • 23:00 - 23:05
    you, you know, a time in milliseconds of completion.
  • 23:05 - 23:08
    And this one I think is, I was working
  • 23:08 - 23:13
    on a Tinder API Client for fun, so. That's
  • 23:13 - 23:15
    what these requests are for. So, that one's
    actually
  • 23:15 - 23:18
    up on my GitHub, too, if you're curious.
  • 23:18 - 23:20
    So, I use that a lot. But if you
  • 23:20 - 23:24
    like to stay command line based, I would recommend
  • 23:24 - 23:30
    HTTPie. It's basically an easier-to-use version
    of curl, and
  • 23:30 - 23:32
    it doesn't have, like, quite the archaic syntax
    curl
  • 23:32 - 23:35
    has. So, I think it's, you know, worthy. Worthy
  • 23:35 - 23:38
    of use. And, you know, it'd be easier, obviously,
  • 23:38 - 23:40
    you know, to run a script around this than
  • 23:40 - 23:42
    it would be to run it around Postman. So
  • 23:42 - 23:44
    if you need to do something more programatic,
    this
  • 23:44 - 23:47
    is probably your best option.
  • 23:47 - 23:50
    And, one last tool I really like to use
  • 23:50 - 23:54
    is called Charles. And Charles does a lot
    of
  • 23:54 - 23:57
    the same things as Chrome Dev Tools does,
    but
  • 23:57 - 24:01
    it acts as a proxy. So it basically captures,
  • 24:01 - 24:04
    you know, requests between you and your network.
    So
  • 24:04 - 24:06
    you can set this up to capture any request
  • 24:06 - 24:11
    from your Mac machine, or you can proxy in
  • 24:11 - 24:14
    your phone as well. So I found this really
  • 24:14 - 24:17
    valuable when I was testing out the request
    from
  • 24:17 - 24:21
    the Snapchat client, because it allowed me
    to see
  • 24:21 - 24:23
    what my phone was making for requests and
    record
  • 24:23 - 24:25
    those. And especially when we didn't know
    what the
  • 24:25 - 24:29
    request was, it was very helpful in that case.
  • 24:29 - 24:32
    And it's also cool because, you know, when
    you're
  • 24:32 - 24:36
    building an API on Ruby and you want to
  • 24:36 - 24:38
    build on iOS client with it, and you're not
  • 24:38 - 24:40
    really sure how often to pull and stuff, I
  • 24:40 - 24:42
    sometimes pull this up, and I'll just see
    what
  • 24:42 - 24:45
    other apps are doing. So it's a good way
  • 24:45 - 24:47
    of debugging other peoples work and, you know,
    seeing
  • 24:47 - 24:51
    how they're doing it well. So, I highly recommend
  • 24:51 - 24:54
    you check it out. It's pretty easy to use,
  • 24:54 - 24:57
    and you can use it with SSL requests as
  • 24:57 - 24:58
    well.
  • 24:58 - 25:01
    So, here's some additional reading. I know
    you won't
  • 25:01 - 25:02
    have time to write this all down. I'll post
  • 25:02 - 25:08
    the slides on my Twitter. But, next up, let's
  • 25:08 - 25:10
    bring it all together.
  • 25:10 - 25:13
    So, we went over the what, the why, and
  • 25:13 - 25:16
    the how of testing services. So, we've shown
    that
  • 25:16 - 25:20
    testing services is crucial. They make up
    really important
  • 25:20 - 25:22
    parts of your app, so skipping tests is pretty
  • 25:22 - 25:25
    dangerous. I'd have to say, if you're in doubt,
  • 25:25 - 25:30
    stub it out. Determine, when you're making
    choices between,
  • 25:30 - 25:35
    you know, web-mock, sham_rack, or puffing-billy,
    even, you want
  • 25:35 - 25:38
    to determine the amount of flexibility the
    need and
  • 25:38 - 25:40
    the amount of extra work you're going to have.
  • 25:40 - 25:43
    For example, it probably takes more time to
    make
  • 25:43 - 25:47
    a sham_rack server and have dynamic responses
    than copying
  • 25:47 - 25:53
    and pasting the request you get from the web-mock
  • 25:53 - 25:55
    error. So, you kind of just need to look
  • 25:55 - 25:57
    at the project you have and determine what
    use
  • 25:57 - 26:01
    case best fits these options.
  • 26:01 - 26:05
    And, also, record responses to save time.
    I wish
  • 26:05 - 26:07
    I would have started doing this sooner. It's,
    like,
  • 26:07 - 26:11
    super useful. I would highly recommend you
    do that.
  • 26:11 - 26:14
    And next up, after me, I'd recommend you stick
  • 26:14 - 26:17
    around. I had the pleasure of pairing with
    Austin
  • 26:17 - 26:21
    yesterday, and I think his talk plays off
    my
  • 26:21 - 26:24
    talk a lot, in that it talks a lot
  • 26:24 - 26:26
    about inconsistent test failures. And he goes
    a lot
  • 26:26 - 26:30
    more in-depth on, you know, other kinds of
    inconsistent
  • 26:30 - 26:33
    test failures. And you just should definitely
    stick around
  • 26:33 - 26:35
    if you have the time.
  • 26:35 - 26:38
    So that's it for today. Thank you for taking
  • 26:38 - 26:41
    the time to listen to my talk. And if
  • 26:41 - 26:43
    I don't get to your question, feel free to
  • 26:43 - 26:44
    shoot me an email, or if you just want
  • 26:44 - 26:46
    to chat. And you can also find me on
  • 26:46 - 26:47
    Twitter. So thanks a lot guys.
Title:
RailsConf 2014 - Effectively Testing Services by Neal Kemp
Description:

more » « less
Duration:
27:15

English subtitles

Revisions