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?
CodePudding user response:
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);
}
}
CodePudding user response:
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);
}
CodePudding user response:
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)
).