Cookin' with Ruby on Rails - Designing for Testabilityby Bill Walton
Editor's Note: This series continues with Cookin' With Ruby on Rails: More Designing for Testability.
NOTE TO READER: This tutorial is intended for use with Rails 1.2.6. It has not yet been updated to support Rails 2.x.
CB has just finished lunch and is thinking "As much as I like the pizza Boss brings by, it'll be even nicer to get to work with Rails 'on the clock'." And just as expected, Paul knocks on the cube 'door,' ready to pick up where they left off at their last session.
Paul: Hi, CB. Ready to get started?
CB: Hi, Paul. You bet. You ready to put on your tester hat?
Paul: Sure. Like you said, it could be a good way for me to get familiar with Rails. I'm not sure I understand what you meant when you said the tester role would be a "natural fit" for me because of the regular contact I have with Boss, though. You wanna say a little more about that?
CB: To tell you the truth, Paul, I'm hoping you'll help me convince Boss to try a different approach to testing. A few years back we had a lot of focus in our product development, manufacturing, and warranty repair groups on testing. I think we called the program Design for Testability. The premise was that the more testable a design was, the cheaper it would be to build and support and the faster we'd get it to market. And it proved out. I think the same general approach will work for software. And I'm hoping you'll help me get Boss onboard. The approach I'd like to see us using advocates writing the Customer Acceptance tests before the developers write application code. Your "day job" puts you in contact with Boss on a regular basis. I'm hoping you'll be able to use some of those encounters to get Boss writing Acceptance tests as part of his giving us Requirements.
Paul: Well, CB, I'm not sure I'm following you entirely. But to tell you the truth, as a project manager, I'm pretty frustrated with the current state of things around here. Seems like most of my big projects go pretty much the same way. Everything's going along fine and then we get to testing. As soon as the customer gets their hands on the software, the schedule goes to hell. Customer says there's a bug. Developer says it's working the way the requirements say it's supposed to work. And then the "he said, she said" starts. And I get to sit in meetings with Boss and his bosses and explain why I can't bring the project in on schedule and budget. So, if you think that by me taking on the tester role on this little project, I'll learn something that can help me make that better, I say, let's get to it!
CB: Cool! I've already got Instant Rails started. How about you take the keyboard, start the web server and then make sure our app's still working?
Paul: No problem. Let's see... start Mongrel,
then browse to our app.
Paul: Looks OK to me. You want me to bounce around a bit and make sure it's all still working like it was before?
CB: You sure you can remember exactly how it worked before?
Paul: Well, this is a pretty simple app right now, and it hasn't been that long since our last session, but I think I get your drift. In fact, that's another one of the ways we get into trouble testing our big projects. Customer comes in, hasn't touched the app in a while, and next thing I hear is, "That's not the way it used to work. That's a bug!" Developer says, "That's the way it's always worked." Then I get to go digging through test plans to see if maybe there's something in there that'll help me get closure.
CB: Yep. So, how's the test plan thing workin' for ya?
Paul: They take a long time to produce. It's hard to get customers to write them, especially with any real detail, so I'm having to hire folks to help them. I'm using contractors right now, but it's starting to look like that's just opening up a real can of worms. The customer groups are starting to make noises about Boss needing a dedicated test group to write the test plans and do most of the testing for them. Any discussion about adding headcount for testing doesn't sit real well with Boss and his bosses, of course. It's starting to feel like a real tar ball.
CB: Yep. Documenting test plans and "monkey on the keyboard" manual test execution doesn't fit most folks' idea of a good time. Speaking of time, how long's it going to take you to make sure our little app still works right?
Paul: I don't imagine it'll take more than a few minutes for this little thing. Not like my "day job" projects. Heck, right now we're in the middle of an end-to-end test on our ERP system. It takes half a dozen customers testing full time for almost a week just to make one pass through it. This'll be a breeze. Three or four minutes tops.
CB: Cool. I'm going to go grab us soda while you do that. Be right back.
CB walks off grinning, thinking, "By the end of this session, Paul's going to be well on his way to becoming a convert."
CB: You done?
Paul: Yeah, everything looks like it's working like it was. How about giving me an idea of where we're headed? I mean, I know we're going to be doing automated testing. But that's about all I know at this point. How's that work in Rails? One of the testers I've brought in is talking up GUI test tools. This anything like that?
CB: Arghhh... no!!! Now don't get me wrong. I'm not saying those tools don't have their place. I've got a buddy who's working on a "green screen" app across town. His boss wants to put test automation in place and they really don't have any option but to test through the UI. There's just no other way to exercise the app in his situation. But Rails gives us much better options. For starters, Rails has a test framework built in. It's not something in addition to Rails. It's an integral part of Rails. And it fully supports automated testing of the MVC pattern that Rails uses. It may take a little getting used to the terminology, though. Rails uses terms that may be familiar, but that mean something different than you might be used to. We'll test our Models using what Rails calls Unit tests. In Rails, Unit test means code that tests the functioning of a Model. Functional test means code that tests the functioning of a controller. And Integration tests means code that tests the functioning of the application across controllers. Some folks take exception to these words being used differently than they're used to. My take on it is that the terms make a lot of sense in the context of the MVC pattern that's being tested. It'll get easier to understand once we get into it, so what do you say we just get started?
Paul: Sounds good. So what's our first step?
CB: First thing we need to do is set up our test database.
Paul: Oh, great ;-(. I figured you'd already have that done. Now I'm thinking I should have blocked out a bigger chunk of time this afternoon.
CB: Settle down, big guy ;-). You've seen how easy development with Rails is, right? And I just told you that test automation is integral to Rails, right? Watch how easy Rails makes it.
We're going to have a dedicated database for our testing. I'll get more into this later, but for now it's important just to understand that the contents of our test database are going to get deleted and rebuilt every time we run our tests. So, we need to make real sure we're running our tests against the test database and not our development or production databases. Remember the database configuration we talked about the first time we worked on this? Let me pull up the file.
CB: So the first thing we need to do is to create the database. We'll do it using the MySQL command line just like we did it for the development database. First, we'll open a new command window, then login to MySQL as root with no password. I know that we really should be using a password, but since I'm the only one right now who even has access to the system, I don't think the security police will be too upset ;-). We'll add a password as soon as the situation changes to warrant it.
mysql -u root -p
Hit enter at the password prompt...
Then create the database.
create database cookbook2_test
Oops, forgot the semicolon
Do the grant to
'ODBC' just so we don't run into that avoidable problem. (I really wish I understood why some Windows systems have a problem if we don't do this and others don't.)
grant all on cookbook2_test.* to 'ODBC'@'localhost';
And we're done with that.