Return to Video

5.2 - FIRST, TDD and Getting Started with RSpec

  • 0:00 - 0:04
    Okay, so we're gonna start with this very
    hands on approach to testing. Testing is a
  • 0:04 - 0:09
    thing that I, I have to admit it's really
    just three or four years ago that I got
  • 0:09 - 0:13
    religion about it, and what I mean by that
    is I always sort of, you know, I was told
  • 0:13 - 0:17
    it was important, I believed it was
    important, I kinda tried to do it but
  • 0:17 - 0:21
    doing it this way really changed my life
    and I hope it will change yours too and
  • 0:21 - 0:25
    no, I'm not on the presidential campaign,
    this is a, anyway, okay So, let's start
  • 0:25 - 0:29
    talking about unit tests. There's some
    background in the book about the different
  • 0:29 - 0:33
    kinds of testing. We'll focus initially on
    unit tests and a little bit on functional
  • 0:33 - 0:37
    tests and, as with so many things in this
    class, there's a handy acronym that helps
  • 0:37 - 0:41
    us remember what good unit tests should
    be. So one of them is they should be fast,
  • 0:41 - 0:44
    shouldn't take a long time to run them.
    They should be independent, that means
  • 0:44 - 0:48
    that running one test before another
    shouldn't make any difference. The order
  • 0:48 - 0:51
    in which you run them shouldn't have
    dependencies on each other. They should be
  • 0:51 - 0:55
    repeatable, if a test finds a bug it
    should find that bug every time. In some
  • 0:55 - 1:01
    cases it's easy to do this, in other cases
    it's surprisingly subtle. Self-checking.
  • 1:01 - 1:05
    What testing used to mean, not that long
    ago for many companies, is that software
  • 1:05 - 1:09
    got thrown over the wall to this QA
    department. And then people in QA would
  • 1:09 - 1:12
    sort of manually poke at the software and
    do things. And yep that work. Yep, that
  • 1:12 - 1:16
    worked. That, we don't do that anymore,
    right? The test code has to know itself if
  • 1:16 - 1:20
    it passed or failed. No human intervention
    should be required to make that decision.
  • 1:20 - 1:24
    And timely. That means that the test
    should be written right around the same
  • 1:24 - 1:27
    time the code was written. If the code
    changes, the test change right away. In
  • 1:27 - 1:31
    fact, we're actually gonna do it even more
    aggressively. We're gonna write the test
  • 1:31 - 1:34
    first, before the code is written. So
    that's as timely as you can be. It's like
  • 1:34 - 1:38
    time warp delivery. So, what does this
    mean? Because, if tests are fast, why do
  • 1:38 - 1:42
    you want that? Well, it's because you can
    run a subset of the tests all the time. If
  • 1:42 - 1:46
    you have thousands and thousands of unit
    tests, which is not uncommon, even in a
  • 1:46 - 1:50
    medium sized project. It could take, you
    know, a minute or two to run the entire
  • 1:50 - 1:53
    test sweep, and that really slows you
    down. What you want is to be able to
  • 1:53 - 1:57
    quickly run just the tests that apply to
    the piece of code you're working on, and
  • 1:57 - 2:01
    not have that sort of take you out of
    rhythm. Independent. For that same reason,
  • 2:01 - 2:05
    you want to be able to run any subset and
    you want to be able to run them in any
  • 2:05 - 2:09
    order. So, it would be bad if there was a
    set of tests that only worked properly
  • 2:09 - 2:13
    provided you ran some other tests ahead of
    them. Repeatable. You know, again, run it
  • 2:13 - 2:17
    N times, get the same results. If you
    wanna isolate bugs, and enable automatic
  • 2:17 - 2:21
    debugging, repeatability is essential.
    Self-checking, like I said. No human
  • 2:21 - 2:25
    checking of the output. This means that
    you can sort of have tests running in the
  • 2:25 - 2:29
    background all the time. And whenever you
    change something that breaks something 25
  • 2:29 - 2:33
    miles away in another piece of code, some
    tests will detect that fact, and pick it
  • 2:33 - 2:37
    up and bring it to your attention. And
    timely, like I said, we're going to use
  • 2:37 - 2:41
    test-driven development, where we write
    the test before we write the code. So,
  • 2:41 - 2:46
    acronym heaven. We're going to be using
    our spec, which I think of as a domain
  • 2:46 - 2:50
    specific language for writing tests. For
    those of you who aren't familiar with
  • 2:50 - 2:54
    DSL's, it's basically like a small
    programming language that only does a
  • 2:54 - 2:58
    small number of things within one task
    domain. So it doesn't try to be general,
  • 2:58 - 3:03
    and we've actually seen examples of them
    so far. Migrations are kind of a DSL,
  • 3:03 - 3:06
    right. There's a, a small set of
    statements whose sole job is to express
  • 3:06 - 3:11
    changes to the database schema. Now
    migrations happen to be a D.S.L. That is
  • 3:11 - 3:15
    embedded in Ruby. Meaning, migrations are
    just Ruby code, but they're stylized to
  • 3:15 - 3:19
    look like the tasks they do. And, in fact,
    we'll see that our spec is a, a similar
  • 3:19 - 3:23
    example. So we'll call those an internal
    DSL. It's implemented inside of another
  • 3:23 - 3:28
    language. Regular expressions are another
    internal DSL, right? There's, like, this
  • 3:28 - 3:33
    little sub vocabulary of things you can do
    in regular expressions. Different example
  • 3:33 - 3:36
    of an external or a stand-alone DSL is
    SQL. Sequel queries for databases, right,
  • 3:36 - 3:40
    that, it's own language and those of you
    who have worked with other frameworks
  • 3:40 - 3:45
    before coming to Rails, usually what you
    end up doing is essentially writing sequel
  • 3:45 - 3:48
    queries and then passing off a string to
    someone, right? So that's a very clear
  • 3:48 - 3:52
    example of dealing with different
    languages. [cough] So in R spec, each test
  • 3:52 - 3:57
    is called a spec, for a specification.
    Surprisingly, they inhabit a directory
  • 3:57 - 4:02
    called spec because we like to keep things
    simple. And there's a rails generator, R
  • 4:02 - 4:06
    spec install that creates the sub
    directory structure. So this is all in the
  • 4:06 - 4:11
    book and we'll assume for some of the live
    demos we're doing today that we've kind of
  • 4:11 - 4:15
    done these set up steps. So where do
    things go? The spec directories are
  • 4:15 - 4:20
    designed to basically mimic where things
    go in your applications, so you know in
  • 4:20 - 4:24
    apps/models you have your models, in
    spec/models you have a spec file for each
  • 4:24 - 4:29
    model, not surprising. Similarly for
    controllers we have controller specs, and
  • 4:29 - 4:33
    what about views? Well we're not really
    gonna do view specs, it's possible to do
  • 4:33 - 4:38
    them, but they're a little bit important
    to write, a lot of what you want to check
  • 4:38 - 4:43
    in a view is stuff that you can actually
    do in a controller spec which we'll see an
  • 4:43 - 4:47
    example of today. And besides, we've
    decided that our push for writing these
  • 4:47 - 4:51
    user-facing web apps is we're doing user
    stories to express the parts of the app
  • 4:51 - 4:54
    that the customer can directly interact
    with. So, things that are part of the
  • 4:54 - 4:58
    view, what should be visible in the view
    and what should be clickable and so forth,
  • 4:58 - 5:02
    we've been using Cucumber for that and
    we're gonna continue to do so. So for the
  • 5:02 - 5:06
    most part we're gonna restrict our
    attention and our spec to writing specs
  • 5:06 - 5:09
    for our models and specs for our
    controllers. So we'll start with an
  • 5:09 - 5:13
    example of a new hypothetical feature for
    rotten potatoes, where we can add movies
  • 5:13 - 5:18
    using information gleaned from TMDB. Tmdb
    is a real site. It is a lot like IMDB. But
  • 5:18 - 5:22
    it's a non-commercial, sort of open source
    one. And the idea is that they have all
  • 5:22 - 5:27
    this information about movies. So if we
    want to add movies to rotten potatoes? Why
  • 5:27 - 5:31
    don't we just scrape the information from
    there? And in fact, when you, talked about
  • 5:31 - 5:36
    user stories, there is a, a step in one of
    the user stories that says, I'm filling in
  • 5:36 - 5:41
    search terms. I'm gonna search for the
    movie, Inception. And then I press this
  • 5:41 - 5:45
    button that says search TMDB, right? So
    that's supposed to be the button that will
  • 5:45 - 5:49
    somehow go off to TMDB, and see if
    Inception is in there, and pull it back.
  • 5:49 - 5:53
    So. The question is: What is? What do we
    need to do? What kind of code needs to be
  • 5:53 - 5:57
    written? And what kind of testing is
    entailed by getting this statement that is
  • 5:57 - 6:01
    in red to work? And before we launch into
    this, remember when we talked about Rails
  • 6:01 - 6:05
    Cookery? Sort of recipes for doing things
    in rails? Remember that when we add any
  • 6:05 - 6:09
    kind of new feature that means we need a
    new route. We need a new controller
  • 6:09 - 6:13
    method. And we may or may not need a new
    view depending on whether the feature can
  • 6:13 - 6:17
    re-use an existing view or, or we have to
    do something new. But these are the steps
  • 6:17 - 6:21
    we always follow. So let's start with
    these one at a time. Okay so, this is an
  • 6:21 - 6:25
    idea that we're gonna see many, many
    times. I'll just get to use to the phrase.
  • 6:25 - 6:30
    To the code you wish you had. It is an
    immensely powerful idea once you get used
  • 6:30 - 6:34
    to do. It feels weird to do things this
    way when you start but it's very powerful.
  • 6:34 - 6:38
    So we ask ourselves okay when the user
    clicks on that button for search TMDB. We
  • 6:38 - 6:42
    know that somewhere there's going to be a
    controller action that receives whatever
  • 6:42 - 6:46
    that form submission was. So what should
    that method do? What should the controller
  • 6:46 - 6:49
    method do that receives the search form?
    Well, if you just kind of ask, you know,
  • 6:49 - 6:53
    in English, if we wrote down what it
    should do, we'd say well, let's see. It
  • 6:53 - 6:56
    should call some method, which we haven't
    written yet, that will actually go out to
  • 6:56 - 7:00
    TMDB and actually search for the movie.
    Make sense? If it finds a movie, it should
  • 7:00 - 7:04
    render some kind of a view with the search
    results for displaying the match. Again,
  • 7:04 - 7:07
    we haven't created that view, but
    logically this is just what we're going to
  • 7:07 - 7:11
    write down that it should do. And we're
    not going to have time to do a step three
  • 7:11 - 7:16
    today, but this sort of sad path, is if it
    doesn't match, if you're redirect to rock
  • 7:16 - 7:20
    potatoes home page and say I didn't find
    anything. And if you look through the
  • 7:20 - 7:24
    example in the book, we actually did the
    sad path in the BDD chapter. So, given
  • 7:24 - 7:28
    that these two things, lets focus on
    number one and number two, are the things
  • 7:28 - 7:33
    that the controller method should do,
    here's how we would express. Where's my
  • 7:33 - 7:39
    mouse? There we go. Here's how we would
    express those should. Using R spec and,
  • 7:39 - 7:44
    okay, so not a lot going on here and, you
    know it's pretty straight forward, right?
  • 7:44 - 7:49
    And this is legal R spec code, Spec Helper
    is just a file that R spec creates as part
  • 7:49 - 7:53
    of that install step. It does some
    housekeeping things to make sure
  • 7:53 - 7:57
    everything's loaded up. And we're gonna
    start by saying, what is this test about?
  • 7:57 - 8:02
    Are we gonna describe the behavior of the
    movies controller? And the controller is
  • 8:02 - 8:06
    gonna have a lot of different behaviors,
    but the one that we're concerned about
  • 8:06 - 8:10
    here is the behavior of searching TMVB. So
    you can imagine for each different
  • 8:10 - 8:13
    behavior in the controller as our spec
    grows we're gonna add more describe blocks
  • 8:13 - 8:17
    inside of this, this outer most one
    describe movies controller and you can
  • 8:17 - 8:22
    keep nesting, nesting, nesting. And all I
    did here was transcribe. Three things that
  • 8:22 - 8:26
    we said it should do. So it is actually a
    method called R spec and it takes an
  • 8:26 - 8:30
    argument, which is a string describing,
    what should happen. And as we'll see in a
  • 8:30 - 8:34
    moment, it also takes a second argument,
    which is a procedure that does that actual
  • 8:34 - 8:37
    task. But for now, all we've done is
    transliterate. We've thought of three
  • 8:37 - 8:41
    things the controller method should do. We
    wrote those three things in our spec. This
  • 8:41 - 8:45
    is actually enough to run, and there's a
    screen cast that I encourage you to watch,
  • 8:45 - 8:49
    that's associated with the book chapter,
    that does exactly that. All it does is run
  • 8:49 - 8:53
    the three tests, and the tests don't do
    anything, so our spec prints them out in
  • 8:53 - 8:56
    yellow. Right. Yellow is not yet
    implemented, just like it was for
Title:
5.2 - FIRST, TDD and Getting Started with RSpec
Description:

In this video, Armando introduces the five attributes of good unit tests, describes test-driven development and begins the RSpec demonstration.

more » « less
Video Language:
English

English subtitles

Revisions