Grouping contexts with Minitest
Dwight Watson
Dwight Watson
Context blocks are a useful RSpec feature for grouping related tests. Most frequently I use context blocks to group request specs by guest/authenticated/authorized groups to ensure my endpoints behave appropriately for each cohort. Here is a rudimentary example that reflects how I might previously test a Posts endpoint with RSpec. Generally I'd keep the expectations distinct so a single change should explain exactly what failed.
RSpec.describe "Posts", type: :request do
context "as guest" do
describe "POST #create" do
it "does not create a new post" do
expect {
post posts_path, params: { post: { title: "Title" } }
}.to_not change(Post, :cont)
end
it "returns forbidden response" do
post posts_path, params: { post: { title: "Title" } }
expect(response).to have_http_status :forbidden
end
end
end
context "as user" do
before { sign_in create(:user) }
describe "POST #create" do
it "creates new post" do
expect {
post posts_path, params: { post: { title: "Title" } }
}.to change(Post, :count).by(1)
end
end
it "redirects to posts#show" do
post posts_path, params: { post: { title: "Title" } }
expect(response).to redirect_to post_url(Post.last)
end
end
end
How might we achieve this context idea in Minitest? I've been looking for options, but so far I've found and enjoyed using subclasses.
class PostsControllerTest < ActionDispatch::IntegrationTest
class Guest < self
test "should not create post" do
assert_no_changes -> { Post.count } do
post posts_path, params: { post: { title: "Title" } }
end
assert_response :forbidden
end
end
class Authenticated < self
setup do
sign_in create(:user)
end
test "should create post" do
assert_changes -> { Post.count } do
post posts_path, params: { post: { title: "Title" } }
end
assert_redirected_to posts_url(Post.last)
end
end
end