I know how to run functional/integration tests in Rails, this question is about best practices. Let's say authorization is performed using four distinct user roles:
This means that for each action there are up to five different behaviors possible (4 roles + unauthenticated/anonymous). One approach I've taken is to test every role on every action, for example:
test_edit_by_anonymous_user
test_edit_by_basic_user
test_edit_by_editor_user
test_edit_by_admin_user
test_edit_by_super_user
But this obviously leads to a lot of tests (every controller action on the site really needs to be tested five times). The opposite approach would be to test the authorization mechanism in isolation and then authenticate as super before testing every action (on setup), and only test one version of each page.
I've tried several approaches with varying degrees of specificity but haven't been completely satisfied with anything. I feel more comfortable when I'm testing more cases, but the amount of test code and difficulty of abstraction has been a turn-off. Does anyone have an approach to this problem that they're satisfied with?
The easiest way to see functional tests in action is to generate a controller using the scaffold generator: $ bin/rails generate scaffold_controller article title:string body:text ... create app/controllers/articles_controller.rb ... invoke test_unit create test/controllers/articles_controller_test.rb ...
There are 6 request types supported in Rails functional tests: All of request types have equivalent methods that you can use. In a typical C.R.U.D. application you'll be using get, post, put, and delete more often. Functional tests do not verify whether the specified request type is accepted by the action, we're more concerned with the result.
By running your Rails tests you can ensure your code adheres to the desired functionality even after some major code refactoring. Rails tests can also simulate browser requests and thus you can test your application's response without having to test it through your browser. Testing support was woven into the Rails fabric from the beginning.
Rails creates a test directory for you as soon as you create a Rails project using rails new application_name. If you list the contents of this directory then you shall see: The helpers, mailers, and models directories are meant to hold tests for view helpers, mailers, and models, respectively.
It really depends on how you have setup your code for checking the authorization and how you test for it in actions. I can tell you what we do as an example. We have roles like you do, and some pages that require login, some that require a role, and some that have different output based on role. We test each type a little differently.
First, we test authorization and login separately.
Also, we created filters for actions that require the user has logged in, and then others for requiring a certain role. For example check_admin
, check_account_owner
, etc. We can then test that those filters work on their own.
We then add checks in the controller tests that the correct filters are being called. We use shoulda and wrote some easy extensions so we can add checks like:
should_filter_before_with :check_admin, :new
That way we are testing what needs to be tested and no more.
Now, for more complex actions that do different logic depending on role, we do test those actions for each role that contains special logic. We don't write tests for roles on that action that will be filtered, or are supersets of other roles. For example if the action adds more fields to a form if you are an admin, we test non-admins and admin. We don't test admin and super admin since our code for role checking understands that super-admins are admins.
Also, for templates that contain logic to only display certain items for certain roles, we try and move that code into helpers, or if common like an admin toolbar, into partials. Then we can test those on their own and not on every action that includes them.
To sum up, test only what you need to for a given action. Just like you wouldn't test Rails internals in your Unit tests, if you write common code for your role checks and test that, you don't need to test it again on every action.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With