Where/what to test? Mocks, stubs, functional, unit... (in Ruby/Rails)?
I'm trying to test a fairly larg开发者_JAVA百科e Rails app, which I probably should have been doing all along but never felt entirely comfortable with. Now I'm working on a functional test to see if a user is created successfully. Basically, I'd like to test a few things:
- whether the user was saved (i.e., if there's a new record in the DB)
- whether his information (name, email, etc.) is correct
- whether a couple of fields have been automatically added to the database before_create
- whether an email was sent
- whether the email text is appropriate (i.e., substitute's the user's name and activation link in the email template)
As I understand it, unit tests are designed to test models and functional tests should test controllers. Several of the tests I mention above should be unit tests, as I see it -- specifically, I think I can make sure that inputs are correctly mapped to database fields and that the before_create filter works in a unit test with a User model.
Others seem to call for functioanl tests -- whether the email is sent (and possibly its text -- although maybe that belongs in a UserEmail test?) and whether there's a new record.
Here's the question about mocking/stubbing. In the user controller functional test, should I just make sure that user.save is called with the appropriate parameters, or should I test that the DB gets a new record? The former seems to call for a stub and assumes that, since Rails is so well tested, the object will be saved successfully if .save is called on the user model. But the latter (e.g., calling assert_difference) feels more thorough. Which to choose?
Sorry if this is too involved a question -- I understand it's a big topic, but my hope is that understanding a specific (if long) example like this will clarify a whole lot about testing in general.
Thanks!
It's not an easy question to answer. Basically there are two camps in the Rails world. One camp will tell you to use the mock, as it will make your tests faster. The other camp will tell you to test with the database, as it will be more "faithful" as it tests that the database table has the proper columns, which the mock will not do. Both camps will tell you that their style of tests is clearer :-)
My advice is to try one way for a while, then try the other. See what works for you. Above all try to make sure your tests are clear and expressive. You can find hints on how to start testing Rails in this presentation by Gregg Pollack.
The way I like to do my functional tests is to not mock/stub anything. Basically, in general stubbing/mocking is very useful for unit testing, as it allows you to isolate classes or units of functionality. Now when it comes to integration and functional tests, the purpose is to test "actual" classes' interactions so you'd want to avoid mocking/stubbing.
So in your case, I would involve the DB when doing a functional-level test for the user controller. If you decided to stub the persistence layer, I would argue you're unit testing the controller (assuming there are no other dependencies) - such a test would not allow you to catch issues with your persistence layer (e.g., incompatible changes in your DB schema, DB connection issues, etc.).
The bottom line is that both practices are valid, but the appropriate way of doing it depends on what your objective is (i.e., functional, integration or unit testing).
精彩评论