9

I am writing JUnit for a class that references a legacy class via constructor. The legacy class is in a third party jar, so I can't refactor it to make life easier....

This is the class being tested...

public MyClass {

    public String methodToTest(String param) {
        LegacyClass legacy = new LegacyClass(param);
        *..... etc ........*
    }
}

This is what I am trying to do in the mockito JUnit.

public MyClassTest {

    @Test
    public void testMethodToTest() throws Exception {
        LegacyClass legacyMock = mock(LegacyClass.class);
        when(*the LegacyClass constructor with param is called*).thenReturn(legacyMock);
        *.... etc.....*
    }
}

Any ideas on how I can do this ?????

Arend v. Reinersdorff
  • 4,110
  • 2
  • 36
  • 40
Dave
  • 231
  • 2
  • 6
  • 8
  • A constructor returning something? Are you sure? For normal functions the stubbing you suggested should work. – Dirk Jun 09 '11 at 07:04
  • When the "new LegacyClass(param)" code is executed, I want it to return a mock. That way I can test "methodToTest" without actually needing to construct a live LegacyClass. The "when" method may be the wron way to do it. Thats my question, how do I do it ??? – Dave Jun 09 '11 at 22:52
  • Hm, this is rather difficult in this case. If you don't have any chance to pass in the legacy class (i.e. `public String methodToTest(String param, LegacyClass lc)`) or create it by using a factory which you can exchange (inside the methodToTest: `lcFactory.create(param)` which then creates an instance, I don't see a way of testing the method except by its outside behaviour. Both those alternatives can also take a mock created by mockito. – Dirk Jun 10 '11 at 08:15
  • Does this answer your question? [Mockito junit 5 mock constructor](https://stackoverflow.com/questions/64905956/mockito-junit-5-mock-constructor) – tkruse Nov 07 '22 at 17:29
  • Related: https://stackoverflow.com/questions/64905956 – tkruse Nov 07 '22 at 17:29

3 Answers3

9

Make a builder for the LegacyClass:

public class LegacyClassBuilder {

    public LegacyClass build(String param) {
        return new LegacyClass(param);
    }

}

That way your class can be tested so it creates the LegacyClass with correct parameter.

public MyClass {

    private LegacyClassBuilder builder;

    public setBuilder(LegacyClassBuilder builder) {
        this.builder = builder;
    }

    public String methodToTest(String param) {
        LegacyClass legacy = this.builder.build(param);
        ... etc
    }
}

The test will look something like this:

// ARRANGE
LegacyClassBuilder mockBuilder = mock(LegacyClassBuilder.class);
LegacyClass mockLegacy = mock(LegacyClass.class); 
when(mockBuilder.build(anyString()).thenReturn(mockLegacy);

MyClass sut = new MyClass();
sut.setBuilder(mockBuilder);
String expectedParam = "LOLCAT";


// ACT
sut.methodToTest(expectedParam);

// ASSERT
verify(mockBuilder).build(expectedParam);

If LegacyClass happens to be final then you need to create non-final wrapper for LegacyClass that MyClass will use.

Spoike
  • 119,724
  • 44
  • 140
  • 158
4

You can use PowerMockito framework:

import static org.powermock.api.mockito.PowerMockito.*;

whenNew(LegacyClass.class)
  .withParameterTypes(String.class)
  .withArguments(Matchers.any(String.class))
  .thenReturn(new MockedLegacyClass(param));

Then write your MockedLegacyClass implementation according to your test needs.

oers
  • 18,436
  • 13
  • 66
  • 75
user1645629
  • 49
  • 1
  • 2
  • See https://stackoverflow.com/questions/64905956 for solution with Mockito but without PowerMockito – tkruse Nov 07 '22 at 17:30
0

I believe it is not possible to mock constructors using Mockito. Instead, I will suggest the following approach:

  public MyClass {

    public String methodToTest(String param) {
     if(legacy== null){
      //when junit runs, you will get mocked object (not null), hence don't initialize 
        LegacyClass legacy = new LegacyClass(param);
      }
        *..... etc ........*
    }
}

public MyClassTest {

@InjectMock
Myclass myclass; // inject mock the real testable class
@Mock
LegacyClass legacy

@Test
public void testMethodToTest() throws Exception {    
    // when(legacy-constructor).thenReturn() ---not Required
    // instead directly mock the required methods using mocked legacy object
    when(legacy.getSomething(Mockito.any(String.class))).thenReturn(null);
        *.... etc.....*
    }
}