javaspringjunitmockitojunit-runner

Java - Spring and Mockito - Mocking a constructor parameter that is not a field in class?


I have the following Spring component that I am trying to unit test:

@Component
public class OrderService {

    private final DatabaseConnection dbConnection;
    private final String collectionName;

    @Autowired
    public OrderService(
            DatabaseConnection dbConnection,
            DatabaseConfig databaseConfig) {

        this.dbConnection = dbConnection;
        this.collectionName = databaseConfig.getCollectionName();
    }
    
    //methods etc...
    
    }

The DatabaseConfig class is as follows:

@ConfigurationProperties(prefix = "database")
@ConstructorBinding
public class DatabaseConfig {

    //methods etc...
}

I am trying to inject mocks in my OrderService class as follows:

@RunWith(MockitoJUnitRunner.class)
class OrderServiceTest {

    @InjectMocks
    OrderService orderService;

    @Mock
    DatabaseConnection dbConnection; // working as expected
    @Mock
    DatabaseConfig databaseConfig; // giving null pointer
    @Mock
    DatabaseCollectionConfig databaseCollectionConfig;

    @BeforeEach
    public void setup() {
        MockitoAnnotations.openMocks(this);

        when(databaseConfig.getCollections()).thenReturn(databaseCollectionConfig);
        when(databaseCollectionConfig.getCollectionName()).thenReturn("myCollection");

    }

When I run my test class I get:

org.mockito.exceptions.misusing.InjectMocksException: 
Cannot instantiate @InjectMocks field named 'OrderService' of type 'class com.my.package.OrderService'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null

The issue is that in the OrderService constructor when I debug this line is coming as null:

 this.collectionName = databaseConfig.getCollectionName();

How can I correctly mock databaseConfig.getCollectionName() to solve the null issue?


Solution

  • No need to use @InjectMock annotation because you are using constructor based injection in your service class. Please rewrite your test case like this and try again.

    
    
    @RunWith(MockitoJUnitRunner.class)
    class OrderServiceTest {
    
        OrderService orderService;
    
        @Mock
        DatabaseConnection dbConnection; // working as expected
        @Mock
        DatabaseConfig databaseConfig; // giving null pointer
        @Mock
        DatabaseCollectionConfig databaseCollectionConfig;
    
        @BeforeEach
        public void setup(){
       when(databaseConfig.getCollections()).thenReturn(databaseCollectionConfig);
    
    when(databaseCollectionConfig.getCollectionName()).thenReturn("myCollection");
    
       orderService = new OrderService(dbConnection, databaseConfig);
    
           
           
    
        }
       }