0

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?

java12399900
  • 1,485
  • 7
  • 26
  • 56

3 Answers3

2

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);

       
       

    }
   }

Rohit Agarwal
  • 763
  • 2
  • 5
  • 10
1

You can try to create a mock for that method and create an object instance instead of using the InjectMocks annotation.

@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);

    }
PR16
  • 39
  • 3
0

Mock behavior, not values. An @ConfigurationProperties class is just a container for data; it doesn't (generally speaking) do anything. Create a real one with new using your test values (e.g., setCollections(testDatabaseCollectionConfig)).

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152