Learn how to set up controller tests in Rails to validate authentication and authorization, ensuring secure and expected application behavior. This video covers structured testing for unauthenticated and authenticated users while debugging and fixing issues in user, post, and comment controllers. With all tests passing, we’re ready to refine the UI and enhance the user experience.
Beyond unit-level model tests, I believe it's essential to define controller-level tests that validate authentication and authorization logic, ensuring that everything behaves as expected.
When you scaffold resources in Rails, it creates two types of tests: system tests and controller tests. Personally, I find system tests, which use a headless browser, to be overkill for most applications. Instead, I prefer using controller tests—they are faster, simpler, and more efficient, though somewhat less flexible. For what we are building, however, they are a perfect fit.
Controller Testing Approach
The pattern I follow for controller tests ensures comprehensive test coverage across the application.
- Every controller gets a dedicated test file—this guarantees that all actions are properly exercised.
- Inside each test, I define two separate classes to test: Unauthenticated users and authenticated users.
By structuring tests this way, I ensure that both types of user experiences are properly covered. Additionally, I make sure to test every RESTful action, even if some of them aren't explicitly defined for a given controller. This helps catch potential edge cases and improves confidence in application stability.
Testing an Unauthenticated User Flow
For unauthenticated users, I set up a test case for a comment controller and walk through each RESTful action:
- Index action: Not defined, so attempting to call the route helper raises a NameError.
- New action: Also undefined, so it should not exist.
- Create action: This should fail for unauthenticated users.
- Show action: The helper method exists, but trying to access it results in a "not found" error.
- Edit, Update, and Destroy actions: These should redirect unauthenticated users to the login page.
Testing an Authenticated User Flow
For authenticated users, I run the same set of tests but with a logged-in user session:
- Set up a test user and authenticate them using a helper method.
- Verify that the user can create a comment (i.e., the comment count should increase by one).
- Ensure that the user is redirected to the correct post after creating or updating a comment.
By using a controller-level authentication helper, I can avoid headless browser testing, making the tests faster and more efficient.
Debugging and Fixing Controller Issues
After running my tests, I found a few failing assertions—something I always expect when tweaking scaffolded controllers.
Fixing User Controller Authorization:
- The user profile (show page) should be visible to unauthenticated users, but the test showed it was redirecting to the login page.
- The issue? The show action wasn't allowing unauthenticated access. I updated the before action to ensure that any user can view profiles while keeping edit/update permissions restricted.
Fixing Post Controller Issues:
- Index and Show actions should be publicly accessible, while New, Edit, Create, and Delete actions should be restricted.
- Updated the controller logic to reflect these rules and re-ran the tests—everything passed!
Fixing Comments Controller Issues:
- The comments path was incorrect—destroying a comment was redirecting to an undefined route.
- Updated the controller so that deleting a comment redirects back to the post page.
Finalizing and Running the Full Test Suite
After making these changes, I re-ran all controller tests for:
✅ Users ✅ Posts ✅ Comments
Everything passed successfully!
Having controller tests in place is a crucial foundation for a production-ready Rails application. These tests:
- Ensure authentication and authorization work correctly
- Provide quick and efficient test coverage
- Catch common edge cases before they become production issues
With solid model and controller tests in place, we can now shift our focus to the view layer, making our application look as polished and user-friendly as possible.