Mock a constructor with parameter

JavaJunitMockingMockitoPowermock

Java Problem Overview


I have a class as below:

public class A {
    public A(String test) {
        bla bla bla
    }

    public String check() {
        bla bla bla
    }
}

The logic in the constructor A(String test) and check() are the things I am trying to mock. I want any calls like: new A($$$any string$$$).check() returns a dummy string "test".

I tried:

 A a = mock(A.class); 
 when(a.check()).thenReturn("test");
 
 String test = a.check(); // to this point, everything works. test shows as "tests"

 whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk);
 // also tried:
 //whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk);

 new A("random string").check();  // this doesn't work

But it doesn't seem to be working. new A($$$any string$$$).check() is still going through the constructor logic instead of fetch the mocked object of A.

Java Solutions


Solution 1 - Java

The code you posted works for me with the latest version of Mockito and Powermockito. Maybe you haven't prepared A? Try this:

A.java

public class A {
	 private final String test;

	public A(String test) {
    	this.test = test;
    }

    public String check() {
        return "checked " + this.test;
    }
}

MockA.java

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class MockA {
	@Test
	public void test_not_mocked() throws Throwable {
		assertThat(new A("random string").check(), equalTo("checked random string"));
	}
	@Test
	public void test_mocked() throws Throwable {
		 A a = mock(A.class); 
		 when(a.check()).thenReturn("test");
		 PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
		 assertThat(new A("random string").check(), equalTo("test"));
	}
}

Both tests should pass with mockito 1.9.0, powermockito 1.4.12 and junit 4.8.2

Solution 2 - Java

To my knowledge, you can't mock constructors with mockito, only methods. But according to the wiki on the Mockito google code page there is a way to mock the constructor behavior by creating a method in your class which return a new instance of that class. then you can mock out that method. Below is an excerpt directly from the Mockito wiki:

> Pattern 1 - using one-line methods for object creation > > To use pattern 1 (testing a class called MyClass), you would replace a call like > > Foo foo = new Foo( a, b, c ); > > with > > Foo foo = makeFoo( a, b, c ); > > and write a one-line method > > Foo makeFoo( A a, B b, C c ) { > return new Foo( a, b, c ); > } > > It's important that you don't include any logic in the method; just the one line that creates the > object. The reason for this is that the method itself is never going > to be unit tested. > > When you come to test the class, the object that you test will > actually be a Mockito spy, with this method overridden, to return a > mock. What you're testing is therefore not the class itself, but a > very slightly modified version of it. > > Your test class might contain members like > > @Mock private Foo mockFoo; > private MyClass toTest = spy(new MyClass()); > > Lastly, inside your test method you mock out the call to > makeFoo with a line like > > doReturn( mockFoo ) > .when( toTest ) > .makeFoo( any( A.class ), any( B.class ), any( C.class )); > > You can use matchers that are more specific than any() if you want to > check the arguments that are passed to the constructor.

If you're just wanting to return a mocked object of your class I think this should work for you. In any case you can read more about mocking object creation here:

http://code.google.com/p/mockito/wiki/MockingObjectCreation

Solution 3 - Java

With Mockito you can use withSettings(). For example if the CounterService required 2 dependencies, you can pass them as a mock:

 UserService userService = Mockito.mock(UserService.class);
 SearchService searchService = Mockito.mock(SearchService.class);   
 CounterService counterService = Mockito.mock(CounterService.class, withSettings().useConstructor(userService, searchService));

Solution 4 - Java

Without Using Powermock .... See the example below based on Ben Glasser answer since it took me some time to figure it out ..hope that saves some times ...

Original Class :

public class AClazz {

	public void updateObject(CClazz cClazzObj) {
    	log.debug("Bundler set.");
	    cClazzObj.setBundler(new BClazz(cClazzObj, 10));
    } 
}

Modified Class :

@Slf4j
public class AClazz {

    public void updateObject(CClazz cClazzObj) {
	    log.debug("Bundler set.");
		cClazzObj.setBundler(getBObject(cClazzObj, 10));
    }

    protected BClazz getBObject(CClazz cClazzObj, int i) {
	    return new BClazz(cClazzObj, 10);
	}
 }

Test Class

public class AClazzTest {

    @InjectMocks
	@Spy
	private AClazz aClazzObj;

    @Mock
    private CClazz cClazzObj;

	@Mock
    private BClazz bClassObj;

	@Before
    public void setUp() throws Exception {
        Mockito.doReturn(bClassObj)
               .when(aClazzObj)
               .getBObject(Mockito.eq(cClazzObj), Mockito.anyInt());
    }

    @Test
    public void testConfigStrategy() {
	    aClazzObj.updateObject(cClazzObj);

	    Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj);
    }
}

Solution 5 - Java

Starting with version 3.5.0 of Mockito and using the InlineMockMaker, you can now mock object constructions:

 try (MockedConstruction mocked = mockConstruction(A.class)) {
   A a = new A();
   when(a.check()).thenReturn("bar");
 }

Inside the try-with-resources construct all object constructions are returning a mock.

Solution 6 - Java

Mockito has limitations testing final, static, and private methods.

with jMockit testing library, you can do few stuff very easy and straight-forward as below:

Mock constructor of a java.io.File class:

new MockUp<File>(){
    @Mock
    public void $init(String pathname){
        System.out.println(pathname);
        // or do whatever you want
    }
};
  • the public constructor name should be replaced with $init
  • arguments and exceptions thrown remains same
  • return type should be defined as void

Mock a static method:

  • remove static from the method mock signature
  • method signature remains same otherwise

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShengjieView Question on Stackoverflow
Solution 1 - JavaAlbanView Answer on Stackoverflow
Solution 2 - JavaBen GlasserView Answer on Stackoverflow
Solution 3 - JavaMevlütÖzdemirView Answer on Stackoverflow
Solution 4 - Javauser666View Answer on Stackoverflow
Solution 5 - JavarieckpilView Answer on Stackoverflow
Solution 6 - JavaAmit KaneriaView Answer on Stackoverflow