Hot questions for Using Mockito in constructor

Question:

I have only parameterized constructor in my code and i need to inject through it.

I want to spy parameterized constructor to inject mock object as dependency for my junit.

public RegDao(){
 //original object instantiation here
Notification ....
EntryService .....
}

public RegDao(Notification notification , EntryService entry) {
 // initialize here
}

we have something like below : 
RegDao dao = Mockito.spy(RegDao.class);

But do we have something that i can inject mocked object in the Constructor and spy it?.


Answer:

You can do that by instantiating your main class with parametrized constructor in your junit and then creating a spy from it.

Let's suppose your main class is A. Where B and C are its dependencies

public class A {

    private B b;

    private C c;

    public A(B b,C c)
    {
        this.b=b;
        this.c=c;
    }

    void method() {
        System.out.println("A's method called");
        b.method();
        c.method();
        System.out.println(method2());

    }

    protected int method2() {
        return 10;
    }
}

Then you can write junit for this using your parametrized class as below

@RunWith(MockitoJUnitRunner.class)
public class ATest {

    A a;

    @Mock
    B b;

    @Mock
    C c;

    @Test
    public void test() {
        a=new A(b, c);
        A spyA=Mockito.spy(a);

        doReturn(20).when(spyA).method2();

        spyA.method();
    }
}

Output of test class

A's method called
20
  1. Here B and C are mocked object that you injected in your class A using parametrized constructor.
  2. Then we created a spy of A called spyA.
  3. We checked if spy is really working by modifying the return value of a protected method method2 in class A which could not have been possible if spyA was not an actual spy of A.

Question:

I am using Mockito to test methods within my Java application.

How can I test that a constructor was called once?

I am trying to do a verification similar to this:

verify(myClass, times(1)).doSomething(anotherObject);

But I can't verify that the constructor was called as it doesn't have a method similar to e.g. doSomething().


Answer:

You can do it with Mockito and PowerMockito.

Say you have ClassUnderTest with a constructor

public class ClassUnderTest {
    String name;
    boolean condition;

    public ClassUnderTest(String name, boolean condition) {
       this.name = name;
       this.condition = condition;
       init();
    }

    ...
}

And another class that calls that constructor

public class MyClass {

    public MyClass() { } 

    public void createCUTInstance() {
       // ...
       ClassUnderTest cut = new ClassUnderTest("abc", true);
       // ...
    }

    ...
}

At the Test class we could...

(1) use PowerMockRunner and cite both target classes above in the PrepareForTest annotation:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassUnderTest.class, MyClass.class })
public class TestClass {

(2) intercept the constructor to return a mock object:

@Before
public void setup() {
    ClassUnderTest cutMock = Mockito.mock(ClassUnderTest.class);
    PowerMockito.whenNew(ClassUnderTest.class)
                .withArguments(Matchers.anyString(), Matchers.anyBoolean())
                .thenReturn(cutMock);
}

(3) validate the constructor call:

@Test
public void testMethod() {
    // prepare
    MyClasss myClass = new MyClass();

    // execute
    myClass.createCUTInstance();

    // checks if the constructor has been called once and with the expected argument values:
    String name = "abc";
    String condition = true;
    PowerMockito.verifyNew(ClassUnderTest.class).withArguments(name, condition);
}

Question:

I'm trying to mock a class constructor with PowerMockito for first time, but it doesn't work. My current code is:

public class Bar {
    public String getText() {
        return "Fail";
    }
}

public class Foo {
    public String getValue(){
        Bar bar= new Bar();
        return bar.getText();
    }

}

@RunWith(PowerMockRunner.class)
@PrepareForTest(Bar.class)
public class FooTest {
    private Foo foo;
    @Mock
    private Bar mockBar;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        PowerMockito.whenNew(Bar.class).withNoArguments().thenReturn(mockBar);
        foo= new Foo();
    }

    @Test
    public void testGetValue() throws Exception {
        when(mockBar.getText()).thenReturn("Success");
        assertEquals("Success",foo.getValue());

    }
}

The test fails because the returned value is "Fail". Where is my problem?


Answer:

Okey, found the answer, you need to call to

@PrepareForTest(Foo.class)

instead of

@PrepareForTest(Bar.class)

Question:

How to get constructor injection in Mockito

I have the following class:

class A{

  private B mB;

  A(B b){
     mB = b;
  }

 void String someMethod(){
     mB.execute();
  }
}

how do I test someMethod using a mock class A and class B using

B b = Mockito.mock(B.class)
Mockito.when(b.execute().thenReturn("String")

A a = Mockito.mock(A.class)
//somehow inject b into A and make the below statement run
Mockito.when(a.someMethod()).check(equals("String"))

Answer:

In my opinion, you're mixing up two ways of testing.

If you want to write a test using Mockito, you just create a mock of some class and use it. This mock doesn't have anything related to a real object as you can (should) mock every method that is called in the test. That's why it doesn't make any sense to mock class B - it is simply not used by class A.

Otherwise, if you want to test a real behavior of class A then why do you want to mock it? Create a real instance of class A with a mocked instance of class B.

That's it! Don't mix it up.

Question:

I have below setup of classes.

class Base {
   @Autowired
   private BaseService service; //No getters & setters
   ....
}

@Component
class Child extends Base {
  private final SomeOtherService otherService;

  @Autowired   
  Child(SomeOtherService otherService) {
     this.otherService = otherService;
  }
}

I am writing a unit test for the Child class. If I use @InjectMocks then the otherService comes out to be null. If I use, the constructor of Child class in the setup of the test, then the fields in Base class comes out to be null.

I know all the arguments about field injection being evil, but I am more interested in knowing if there is a way to solve this without changing the way Base and Child classes injects their properties?

Thanks!!


Answer:

Just do this:

public class Test {
    // Create a mock early on, so we can use it for the constructor:
    OtherService otherService = Mockito.mock(OtherService.class);

    // A mock for base service, mockito can create this:
    @Mock BaseService baseService;

    // Create the Child class ourselves with the mock, and
    // the combination of @InjectMocks and @Spy tells mockito to
    // inject the result, but not create it itself.
    @InjectMocks @Spy Child child = new Child(otherService);

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
    }
}

Mockito should do the right thing.

Question:

I am writing a test case using JUnit and the method under test takes a final class with a private constructor as a parameter. Since I cannot instantiate it with the new keyword I tried using Mockito but found out that Mockito doesn't like final class. I went to use PowerMockito which seemed reasonable to me but PowerMockito.mockStatic(Field.class); is a void method and I need a reference of Field so that I can pass it as an argument while invoking the method.

I want to catch IllegalArgumentException but first I need to pass reference of Field as an argument

Method under test

public boolean accept(Field field) { 
    if( ignoreNulls ) {
        try {
            if( field.get( super.getObject() ) == null ) {
                return false;
            }
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        }
    }

    return super.accept(field); 
} 

JUnit test case

   @Test(expected=IllegalArgumentException.class)
    public void testAccept() throws Exception {
      DefaultToStringBuilder builder = new DefaultToStringBuilder(new Object());
      PowerMockito.mockStatic(Field.class);

      builder.accept(?);
}

I am not sure how should I be doing this.

Thanks in advance


Answer:

My answer don't do that. Do not engage in PowerMock just because your production code can't be tested otherwise.

You will find out soon that PowerMock can create more problems than it solves.

Typically, the need to use PowerMock comes from a broken design. So, instead of spending hours to enable a broken design for testing via PowerMock ... you better spent a fraction of that time in order to rework your design. (and from my one experience: PowerMock can quickly lead to countless hours being spent on it)

Meaning: you could add a package protected constructor for testing purposes. Or you might go one step further to get the broader picture; and find ways that allow for a public constructor; whilst maintaining the design ideas that lead to the current final/private implementation.

Question:

I am trying to use @Mock to inject two different objects into my class under test. I need them to be two different objects so that I can use when on each one to produce different results. Everything I've searched on SO points toward this working, but when running the test below - both objects are the same mock.

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

import com.ihm.pp.test.UnitTest;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

/**
 * @author Josh Johnston
 */
@Category(UnitTest.class)
@RunWith(MockitoJUnitRunner.class)
public class ConstructorInjectionBug {

  @Mock
  private IBroken aBroken;

  @Mock
  private IBroken bBroken;

  @InjectMocks
  private UsesBroken usesBroken;

  @Test
  public void testBrokenConstructorInjection() {

    when(bBroken.getNumber()).thenReturn(2);
    assertEquals(2, usesBroken.getbBroken().getNumber());

    when(aBroken.getNumber()).thenReturn(1);
    assertEquals(1, usesBroken.getaBroken().getNumber());
  }
}

interface IBroken {
  int getNumber();
}

class UsesBroken {

  private IBroken aBroken;
  private IBroken bBroken;

  public UsesBroken(IBroken aBroken, IBroken bBroken) {
    this.aBroken = aBroken;
    this.bBroken = bBroken;
  }

  public IBroken getaBroken() {
    return aBroken;
  }

  public IBroken getbBroken() {
    return bBroken;
  }
}

Result:

java.lang.AssertionError:
    Expected :1
    Actual   :2

at org.junit.Assert.failNotEquals(Assert.java:834)
    at org.junit.Assert.assertEquals(Assert.java:645)
    at org.junit.Assert.assertEquals(Assert.java:631)
    at ConstructorInjectionBug.testBrokenConstructorInjection(ConstructorInjectionBug.java:37)

Answer:

@InjectMocks wont know which IBroken to inject. So it is not that it is broken but more the design is flawed.

You would need to explicitly inject the mocks into the subject under test to get the desired behavior.

@Category(UnitTest.class)
@RunWith(MockitoJUnitRunner.class)
public class ConstructorInjectionBug {

  @Mock
  private IBroken aBroken;

  @Mock
  private IBroken bBroken;

  private UsesBroken usesBroken;

  @Test
  public void testBrokenConstructorInjection() {
    //Arrange
    usesBroken = new UsesBroken(aBroken, bBroken);
    when(bBroken.getNumber()).thenReturn(2);
    when(aBroken.getNumber()).thenReturn(1);

    //Act & Assert
    assertEquals(2, usesBroken.getbBroken().getNumber());    
    assertEquals(1, usesBroken.getaBroken().getNumber());
  }
}

Question:

I am trying to write a test for legacy code that is looking like this:

public class TestedClass {
    private A a = StaticFactory.createA();
    private B b = StaticFactory.createB();
    // No default constructor
    // code using A and B classes
}

As far as my understanding of Mockito goes, I know that I can not mock static methods, however I know that I can use a little trick and externalize creation of this object to package-private methods like this:

public class TestedClass {

    private A a;
    private B b;

    TestedClass() {
        a = createA();
        b = createB();
    }

    A createA() {
        return StaticFactory.createA();
    }

    B createB() {
        return StaticFactory.createB();
    }

    // code using A and B classes
}

But using this construction I am unable to create spy of TestedClass, it has to be already a spy to use doReturn(..) constructions so test like this won`t work:

public class TestedClassTest {

    TestedClass testedClass;

    A mockA;
    B mockB;

    @Before
    public void setUp() {
        mockA = mock(A.class);
        mockB = mock(B.class);

        testedClass = Mockito.spy(new TestedClass());

        doReturn(mockA).when(testedClass).createA();
        doReturn(mockB).when(testedClass).createB();   
    }
}

Is there any other way to change behaviour of createA and createB methods that are getting fired in constructor to ensure that I have mocks instances?

In this case, StaticFactory.createA() is run and it is throwing exception (just under tests), unabling me to finish initialization of tests.

Running pl.tbawor.TestedClassTest
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.168 sec <<< FAILURE!
shouldTestSomething(pl.tbawor.TestedClassTest)  Time elapsed: 0.114 sec  <<< ERROR!
java.lang.NullPointerException
        at pl.tbawor.StaticFactory.createA(TestedClass.java:32)
        at pl.tbawor.TestedClass.createA(TestedClass.java:14)
        at pl.tbawor.TestedClass.<init>(TestedClass.java:9)
        at pl.tbawor.TestedClassTest.setUp(TestedClassTest.java:26)

My goal is to avoid running original methods for creation A and B objects to prevent exception from being thrown.

Also as this is legacy project, I am unable to add any additional libraries (PowerMock).

I`ll add that TestingClass modification should be as little as possible.


Answer:

You have to record a behavior on the spy instance but you do it before creating the spy.

Here :

doReturn(mockA).when(testedClass).createA();
doReturn(mockB).when(testedClass).createB();
testedClass = Mockito.spy(new TestedClass());

testedClass is null when you record behaviors for mocks.

Reverse the order of these statements :

testedClass = Mockito.spy(new TestedClass());
doReturn(mockA).when(testedClass).createA();
doReturn(mockB).when(testedClass).createB();

Besides, this solution will not solve your root problem as the invoked no-arg constructor still depends of dependencies that you want to isolate but that are not yet at this time :

TestedClass() {
    a = createA();
    b = createB();
}

You should refactor a little TestedClass to allow to set dependencies. You could for example overload the constructor :

TestedClass(A a, B b) {
    this.a = a;
    this.b = b;
}

In this way, you could mock dependencies of TestedClass :

@Before
public void setUp() {
    mockA = Mockito.mock(A.class);
    mockB = Mockito.mock(B.class);
    testedClass = new TestedClass(mockA, mockB);
}

Question:

When in a test class we instruct mockito to providing some mock objects (annotating such attribute-fields with @Mock) for the purpose of the testing (maybe to be injected into @InjectMocks attribute-field), what are the rules being followed for creating each mock?

More specifically:

1) how is each mock being built?

2) how are the dependencies of each mock being handled? what rules and limitations should be considered when mocking?

3) The case "mocked class A depends on class B, and class B is in turn mocked (in the same test class)" is different from the case "mocked class A depends on class B and class B is not mocked"?


Answer:

The idea of mocks is exactly the opposite of what your question implies: they are not called by calling your constructors. That is the whole idea of mocks: they have nothing to do with your production code.

In other words: you ask for a mock object of some A.class; and you get an object that supports the methods of A.class. In that sense, a mocked A object doesn't have any dependencies.

You know, that is the whole point: if a mocked A would be the same as a real A; what sense would be in mocking?

Question:

class A {
   public B getB(){
      // somehow get argType1 and argType2
      return new B(argType1, argType2);
   }
}

class B{
   public B(Type1 t1, Type2 t2){
     // something
   }
}

I want to Test A, and verify that constructor of B is getting called for expected values of argType1 and argType2.

How can i do this using PowerMockito?

Is there a way to pass argumentCaptor like this:

whenNew(B.class).withArguments(argType1Captor, argType2Captor).thenReturn(somemock);

if this do this, argType1Captor gets both the values


Answer:

I solved it by doing this

PowerMockito,verifyNew(B.class).withArgument(expectedArgType1, expectedArgType2)

Question:

it is my first question so apologies if I did something wrong. I'm testing a usecase that takes an injected Lazy Dagger constructor parameter.

import dagger.Lazy

class TrackSpeed (val analyticsRepository: Lazy<AnalyticsRepository>) {

    fun execute(timeMillis: Long) {
        analyticsRepository.get().trackSpeed(timeMillis)
    }
}

I don't know how to mock AnalyticsRepository as it is Lazy. This is how my test class looks right now:

class TrackSpeedTest {

private lateinit var trackSpeed: TrackSpeed
private val analyticsRepository: Lazy<AnalyticsRepository> = mock()

@Before
fun setUp() {
    trackSpeed = TrackSpeed(analyticsRepository)
}

@Test
fun testTrackSpeed() {
    val time: Long = 0

    trackSpeed.execute(time)

    verify(analyticsRepository.get(), times(1))
        .trackSpeed(time)
}

There are no compilation errors but when I run the test it fails with this exception:

java.lang.ClassCastException: io.reactivex.internal.operators.flowable.FlowableError cannot be cast to com.package.AnalyticsRepository at com.package.TrackSpeed.execute()

Any suggestions? Thanks in advance.


Answer:

You could create an actual instance of Lazy that returns your mocked AnalyticsRepository in get():

analyticsRepository = mock<AnalyticsRepository>()
val lazy = Lazy<AnalyticsRepository> { analyticsRepository }
trackSpeed = TrackSpeed(lazy)