Reputation: 1204
I'm testing legacy code that looks like this.
class Converter {
static String convert() {
SubConverter.subConvert();
}
}
class SubConverter {
static String subConvert() {
Generator generator = new Generator();
return generator.generate();
}
}
My goal is to test Converter.convert
, mocking generator.generate()
.
The test class looks like this:
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
class ConverterTest {
@Mock
Generator generatorMock;
@Test
public void convertTest(){
MockitoAnnotations.openMocks(this);
Mockito.when(generatorMock.generate()).thenReturn("123");
Converter.convert();
// some assertions
}
}
The actual implementation of Generator.generate()
is used instead of the mock.
I've tried:
import org.mockito.InjectMocks;
@InjectMocks
Converter converterWithMock;
, testing converterWithMock.convert()
, same result.
I've tried with PowerMockito, I can't make it work (maybe I use it the wrong way).
What's the right way to do this?
Using junit-jupiter 5.8.2 and mockito 4.3.1.
Upvotes: 2
Views: 2015
Reputation: 5985
You need to mock constructor of Generator
class.
Solution 1: Using Mockito (Main preferable)
Mockito suports mock construction since 3.5 version. Documentation
Add mockito-inline to your dependencies. It provides ability to generate mocks on constructor invocations.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.3.1</version>
<scope>test</scope>
</dependency>
Mock constructor.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
class ConverterTest {
@Test
public void convertTest(){
//create mock for Generator class constructor
try (MockedConstruction<Generator> mockedGenerator = Mockito.mockConstruction(Generator.class,
(mock, context) -> {
when(mock.generate()).thenReturn("123");
})) {
//execute Converter class under the test
String result = Converter.convert();
//ensure that constructor was executed
Assertions.assertFalse(mockedGenerator.constructed().isEmpty());
//ensure the generate method was executed
verify(mockedGenerator.constructed().get(0), times(1)).generate();
//verify return value
Assertions.assertEquals("123", result);
}
}
}
Solution 2: Using PoserMock
PowerMock does not have JUnit 5 support, only Junit 4.
Example of mocking constructor via PowerMock
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
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(SubConverter.class)
public class ConverterTest {
@Mock
Generator generatorMock; //create Mock
@Test
public void convertTest() throws Exception {
//configure Mock
Mockito.when(generatorMock.generate()).thenReturn("123");
//return mock when constructor is executing
PowerMockito.whenNew(Generator.class).withNoArguments().thenReturn(generatorMock);
//perform Converter under the test
String result = Converter.convert();
//check return value
Assert.assertEquals("123", result);
}
}
Upvotes: 2