2

I have a service object called ResetPassword that handles all the logic for the ResetPassword Controller create action. I also have already tested the service object. Should I mock the service object? I figure I should since it's ready tested and it would cut down on running specs. My test code so far for the controller is below. Not sure if it should be written this way.

require 'spec_helper'

describe ResetPasswordController do
  describe "POST create" do
    context "when email matches a user" do
      let(:user) { Fabricate(:user) }

      it "calls password_reset on PasswordReset" do
        ResetPassword.stub(:reset_password)
        ResetPassword.any_instance.should_receive(:reset_password)
        post :create, email: user.email

      end
      it "redirects to root path" do
        post :create, email: user.email
        expect(response).to redirect_to root_path
      end
    end
    context "when email doesn't match a user" do
      it "redirects to new"
      it "displays a flash error"
    end
  end
end
xlembouras
  • 8,215
  • 4
  • 33
  • 42
user2170878
  • 163
  • 1
  • 9

2 Answers2

1

I think you should mock the service in your controller, but mock it by injecting a mock instead of stubbing on the class or any_instance

Your controller could look like this

class ResetPasswordController < ApplicationController
  def create
    reset_password_service.reset_password(params[:email])
  end

  def reset_password_service
    @reset_password_service ||= ResetPassword.new
  end

  def reset_password_service=(val)
    @reset_password_service = val
  end
end

Then in your spec you can

before { controller.reset_password_service = password_service }
let(:password_service) { double("PasswordService", reset_password: nil) }

it "does something good" do
  post :create, email: "foo"
  expect(password_service).to have_received(:reset_password).with("foo")
end

Or even better, use an instance_double instead. That will also check that the stubbed methods actually exists on the stubbed class. This is available from RSpec 3.0.0.beta*

let(:password_service) { instance_double(PasswordService, reset_password: nil) }
Lasse Skindstad Ebert
  • 3,370
  • 2
  • 29
  • 28
-1

you can use mockito to mock your service and imockit multiple services with mockito.

tony k
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – MD. RAKIB HASAN Dec 09 '21 at 07:01
  • Your answer doesn't actually address the question, which was whether they *should* mock. To answer such a question, you need to do more than point out a couple of options for mocking and instead show how and why it might help (or not help) their situation. Also, be aware that the original question's over 7 years old so the OP has probably moved on! Any answer at this stage really does need to provide substantial updates or context for people who come across the question now. – JohnP Dec 09 '21 at 17:48