I have two class OneClass and AnotherClass:
class OneClass
  def initialize(*args)
    @another_member = AnotherClass.new()
  end
  def my_method()
    if @another_member.another_method1() then
      @another_member.another_method2()
    end
    @another_member.another_method3()
  end
end
I am getting to write unit for OneClass. 
How can I mock @another_member?
Mocking is a technique in test-driven development (TDD) that involves using fake dependent objects or methods in order to write a test. There are a couple of reasons why you may decide to use mock objects: As a replacement for objects that don't exist yet.
A Double is an object which can “stand in” for another object. You're probably wondering what that means exactly and why you'd need one. This is a simple class, it has one method list_student_names, which returns a comma delimited string of student names.
Use let to define a memoized helper method. The value will be cached across multiple calls in the same example but not across examples. Note that let is lazy-evaluated: it is not evaluated until the first time the method it defines is invoked.
With the idea of Anthony, I make it work.
describe OneClass do
  before(:each) { @one_object = OneClass.new }
  describe 'my_method' do
    it 'should work' do
      mock_member = double
      allow(mock_member).to receive(:another_method1).and_return(true)
      @one_object.instance_variable_set(:@another_member, mock_member)
      @one_object.my_method()
      expect(mock_member).to have_received(:another_method1)
    end
  end
end
                        You can't mock an instance variable. You can only mock methods. One option is to define a method inside OneClass that wraps the another_member, and mock that method.
class OneClass
  def initialize(*args)
  end
  def my_method()
    if another_member.another_method1() then
      another_member.another_method2()
    end
    another_member.another_method3()
  end
  private
  def another_member
    @another_member ||= AnotherClass.new()
  end
end
However, you don't have to, there is a better way to write and test your code. In this case a better approach to mocking is to use a pattern called Dependency Injection.
You pass your dependency to the initializer.
class OneClass
  def initialize(another: AnotherClass, whatever:, somethingelse:)
    @another_member = another.new()
  end
  def my_method()
    if @another_member.another_method1() then
      @another_member.another_method2()
    end
    @another_member.another_method3()
  end
end
(Note I used keyword arguments, but you don't have to. You can also use the standard args approach).
Then, in the test suite you simply provide the test object.
let(:test_another) {
  Class.new do
    def another_method1
      :foo
    end
    def another_method2
      :bar
    end
    def another_method3
      :baz
    end
  end
}
it "does something" do
  subject = OneClass.new(another: test_another)
  # ...
end
There are several advantages of this approach. In particular, you avoid using mock in the tests and you really test the object in isolation.
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