Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a method called inside another method?

I would like to explain my problem using an example.

Class A
{
    Fun1()
    {
        // some code
        B obj2 = new B();
        obj2.Fun2();
    }
}

Class B
{
    Fun2() 
    {
        // some code
    }
}

// Test Class for Class A
Class A_Test
{
    Fun1_Test()
    {
        A obj1 = new A();
        A.Fun1();
    }
}

Here I am calling Fun1 which calls fun2(). I want to mock call to fun2().

I need to do initialization of Class B object in Fun1() only, I don't want to do it using constructor.

It is possible to mock call to fun2()?

like image 584
Atul Avatar asked Jun 24 '14 10:06

Atul


People also ask

How do you mock a method call inside another method in the same class?

We can mock runInGround(String location) method inside the PersonTest class as shown below. Instead of using mock(class) here we need to use Mockito. spy() to mock the same class we are testing. Then we can mock the method we want as follows.

Is it possible to call the actual methods after mocking a class?

Mockito allows us to partially mock an object. This means that we can create a mock object and still be able to call a real method on it. To call a real method on a mocked object we use Mockito's thenCallRealMethod().

How do you mock a method?

Mockito when() method It should be used when we want to mock to return specific values when particular methods are called. In simple terms, "When the XYZ() method is called, then return ABC." It is mostly used when there is some condition to execute. Following code snippet shows how to use when() method: when(mock.

What is the difference between @mock and @InjectMocks?

@Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class. Annotated class to be tested dependencies with @Mock annotation.


2 Answers

You can't, because Fun2 is an instance method of an object created inside Fun1.

Since A depends on B, B should be injected into A, if you want to achieve true isolation.

You should also "Depend upon abstractions", as advertised by the Dependency Inversion Principle. Make B implement an interface IB, and make A depend on IB instead. Then, you mock the interface IB and inject that mock instead.

class A
{
    public Fun1(IB ib) { ib.Fun2(); }
}

interface IB
{
    Fun2();
}

class B : IB
{
    public Fun2() {}
}

// Test Class for Class A
Class A_Test
{
    Fun1_Test()
    {
        var bMock = new Mock<IB>();
        bMock.Setup(b => b.Fun2());

        A obj1 = new A();
        A.Fun1(bMock.Object);
    }
}

Read:

  1. Dependency Inversion Principle
  2. Dependency Injection
like image 151
dcastro Avatar answered Oct 27 '22 08:10

dcastro


Classic example which shows how if you cannot unit test a particular component, REFACTOR the component!

This is where is love what any mocking framework enforces you to do - write decoupled code.

In your example, the class A is very tightly coupled with the concrete implementation of B. You could decouple it using (like most of the answers suggest) dependency injection. By doing so, you would end up depending on the IB abstraction than any concrete implementation of it.

like image 43
Amol Avatar answered Oct 27 '22 10:10

Amol