I have a Spring @Service and @Scope("prototype") class named StringCircularQueue, which has a constructor where a variable named queueName is getting initialized and a method addElement as below. To unit test this method inside the class, I am using JUnit Mockito to mock the RedisConnectionConfig which is being used in the addElement method.
When debugging the test, the redisConnectionConfig variable inside the addElement method shows null. But, if I comment out the constructor and run the same, the redisConnectionConfig variable shows a Non Null value.
Unable to figure out what is the issue when using the constructor. Any suggestions could be of great help.
@Service
@Scope("prototype")
public class StringCircularQueue {
@Autowired
private RedisConnectionConfig redisConnectionConfig;
private String queueName;
public StringCircularQueue(String queueName) {
this.queueName = queueName;
}
public Boolean addElement(String element) {
RedissonClient redisClient = redisConnectionConfig.getRedisClient();
// Some other business logic
}
}
public class RedisCircularQueueTest {
@InjectMocks
RedisStringCircularQueue redisStringCircularQueue;
@Mock
private RedisConnectionConfig redisConnectionConfig;
@Mock
private RedissonClient redissonClient;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testAddElementToQueue() {
Mockito.when(redisConnectionConfig.getRedisClient()).thenReturn(redissonClient);
Boolean isAdded = redisStringCircularQueue.addElement("testString");
Assert.assertEquals(true, isAdded);
}
}
CodePudding user response:
Don't rely on field injection but on constructor injection in your StringCircularQueue
as follows:
@Service
@Scope("prototype")
public class StringCircularQueue {
private RedisConnectionConfig redisConnectionConfig;
private String queueName;
public StringCircularQueue(RedisConnectionConfig redisConnectionConfig, String queueName) {
this.redisConnectionConfig = redisConnectionConfig;
this.queueName = queueName;
}
public Boolean addElement(String element) {
RedissonClient redisClient = redisConnectionConfig.getRedisClient();
// Some other business logic
}
}
With this, your test will work.
The reason why it was null
when you have the constructor is the following: Mockito will try to inject mocks only either by constructor injection, property injection or setter injection in this order. If the object is successfully created with the constructor, then Mockito won't try the other strategies, and that is why redisConnectionConfig
is null
because it has to be injected directly into the property itself. When you comment out the constructor, Mockito will only have the default no-args constructor of StringCircularQueue
at its disposal. Since this does not inject anything, Mockito tries property injection, hence you get a non-null redisConnectionConfig
this time. You can read more about this in the official documentation at https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/InjectMocks.html.