We’ve been learning about test-driven-development and RSpec, and it’s been amazing at times, frustrating at others. The frustrations are usually brought about when there’s a test that I want to run, but I don’t yet know how to build that test. We’re going to be learning more over the next few days, and the theory is that our learning curves for Ruby and RSpec will more or less mirror each other.
From talking to professional developers, it seems that learning how to test code is something that people normally learn later on in their programming careers. I’m so glad that I’m learning it earlier on. I think getting comfortable with a test-based workflow from the get-go can only help, and so far I’m really loving testing.
The basic premise of TDD is that before you write your code, you think about how you want your code to behave and then write tests which will define the parameters for how you think your code should act. Not what your code should be, but what the top-level performance and behaviors should be. After your tests are written, you can go ahead and run the code for your tests with RSpec. All your tests should fail, and this is okay! Without failure at this stage, there would be no way to know if your tests actually were working. If you don’t find failure here, something is wrong. Once you make sure your tests fail spectacularly, only then should you write code to make your tests pass.
I’m finding that writing tests breaks up your code into smaller pieces, and forces you to think about what makes sense before you dive in. It can also help you account for outliers and fringe cases. Not sure if you need to account for something in your code? That’s fine, just write a test! If the test passes, then you’re golden. If it fails, you’re still golden, because you now know what isn’t working!
I think one of the reasons I like TDD so much is that it’s like creating a puzzle and then solving it. I’ve always loved puzzles, ranging from jigsaw puzzles to cyphers to lockpicking, and so this is along the same vein as those. I’ve heard various things about TDD in the past, mainly that it’s tedious and frustrating. And while I’m sure that can be the case, I think it actually makes coding easier, especially when you write the tests first, since you’re letting your tests help you influence and simplify your code, instead of just writing tests to justify the code you’ve already wrote. Through the exercises we’ve done, I suspect that I have quite a dislike for writing tests after the code is written. I find it tedious, boring, and frustrating. Tests first changes everything.
The best part of writing tests, though, is that once you get your tests to pass, it’s a lot easier to refactor. Your code is already likely broken up into smaller, testable methods, but having a test suite in place also gives a kind of freedom. You don’t have to worry about everything crumbling because you made a syntax error when refactoring. You can just run your code to make sure everything still works as it should. This ability, combined with the history Git provides, is like adding super powers to your programming toolbox.
So, a quick note on just how to write an RSpec test. As you can see above on line 1, you start by “requiring” another document. This should be a Ruby file – the .rb file extension is assumed. The next step, on line 3, is to state what method (or Class) you’re testing. You use this by writing ‘describe’ and then putting the method name in quotes. Keep in mind, there is no Ruby magic here. The string method is just a string. Finally, you get into the meat of the test. This is the expect statement. It starts with the keyword “it”, and then a string of your description of what the test is supposed to do. What you write doesn’t matter to the code, but it can help you remember what your test does. The next part goes something like: “expect(this_method(with_arguments)).to eq(return_value)”. Expect, to, and eq are all methods that you use to check your code, and this is the part of the test code that’s actually looking to see if your code works. Make sure you have all the it, do, and end keywords, account for other cases that may come up, and there you go, you have a basic test!