依赖列表的 JUnit 测试构造函数注入
JUnit Test Constructor Injection of List of Dependencies
我正在尝试为以下 class 编写测试,其中映射字段是通过构造函数注入和依赖项参数列表注入的。我如何模拟依赖项?
@Component
public class ComponentInputValidator {
private final Map<String, FaceInterface> faceMap;
private final Map<String, ArmsInterface> armsMap;
private final Map<String, MobilityInterface> mobilityMap;
private final Map<String, MaterialInterface> materialMap;
private final RobotComponentStock robotComponentStock;
public ComponentInputValidator(List<MaterialInterface> materialList,
List<FaceInterface> faceList,
List<ArmsInterface> armsList,
List<MobilityInterface> mobilityList,
RobotComponentStock robotComponentStock){
this.faceMap = faceList.stream().collect(Collectors.toMap(faceInterface -> faceInterface.getCode().name(), Function.identity()));
this.armsMap = armsList.stream().collect(Collectors.toMap(armsInterface -> armsInterface.getCode().name(), Function.identity()));
this.mobilityMap = mobilityList.stream().collect(Collectors.toMap(mobilityInterface -> mobilityInterface.getCode().name(), Function.identity()));
this.materialMap = materialList.stream().collect(Collectors.toMap(materialInterface -> materialInterface.getCode().name(), Function.identity()));
this.robotComponentStock = robotComponentStock;
}
public boolean validateStockAvailability(RobotComponent robotComponent){
String face = robotComponent.getFace();
String arms = robotComponent.getArms();
String mobility = robotComponent.getMobility();
String material = robotComponent.getMaterial();
Code faceCode = faceMap.get(face).getCode();
Code armsCode = armsMap.get(arms).getCode();
Code mobilityCode = mobilityMap.get(mobility).getCode();
Code materialCode = materialMap.get(material).getCode();
if (robotComponentStock.getQuantity(faceCode)<1 ...{
...
return false;
}
return true;
}
}
FaceInterface、ArmsInterface、MobilityInterface、MaterialInterface 是具有不同实现的接口。
我尝试了什么:
@MockBean
private RobotComponentStock robotComponentStock;
@MockBean
private List<FaceInterface> faceInterfaceList;
@MockBean
private List<MobilityInterface> mobilityInterfaceList;
@MockBean
private List<ArmsInterface> armsInterfaceList;
@MockBean
private List<MaterialInterface> materialInterfaceList;
@InjectMocks
private ComponentInputValidator componentInputValidator;
出现错误:
org.mockito.exceptions.misusing.InjectMocksException:
无法实例化类型为 'class com.demo.robot_factory.service.ComponentInputValidator' 的名为 'componentInputValidator' 的 @InjectMocks 字段。
您没有在字段声明中提供实例,所以我尝试构建实例。
但是构造函数或初始化块抛出异常:null
对于行
faceList.stream().collect(Collectors.toMap(faceInterface -> faceInterface.getCode().name(), Function.identity()));
您在测试中混合了两个不同的概念。
@MockBean
是 集成测试 中使用的 Spring 注释。它将创建一个模拟,Spring 的正常注入机制会将其注入到您的 Bean 中。
另一方面,@InjectMock
是 单元测试 中使用的来自 Mockito 的注释。
我可以就以下主题推荐此博客 Post:
@Mock vs. @MockBean When Testing Spring Boot Applications
如果您想编写单元测试,我建议将所有 @MockBean
注释替换为 Mockitos @Mock
。
// same for the other dependencies you want to mock
@Mock
private List<MaterialInterface> materialInterfaceList;
@InjectMocks
private ComponentInputValidator componentInputValidator;
这应该可以修复异常。
查看您的代码,我建议您采用完全不同的测试方法。
我不明白你为什么要首先模拟列表。您不能只实例化列表并手动构建 ComponentInputValidator
吗?例如:
@Test
void test(){
List<MaterialInterface> materialList = List.of(...)
//initialize your other dependencies here
//pass all Lists into the constructor
var validator = new ComponentInputValidator(materialList,...)
//make your assertions on the validator
}
我正在尝试为以下 class 编写测试,其中映射字段是通过构造函数注入和依赖项参数列表注入的。我如何模拟依赖项?
@Component
public class ComponentInputValidator {
private final Map<String, FaceInterface> faceMap;
private final Map<String, ArmsInterface> armsMap;
private final Map<String, MobilityInterface> mobilityMap;
private final Map<String, MaterialInterface> materialMap;
private final RobotComponentStock robotComponentStock;
public ComponentInputValidator(List<MaterialInterface> materialList,
List<FaceInterface> faceList,
List<ArmsInterface> armsList,
List<MobilityInterface> mobilityList,
RobotComponentStock robotComponentStock){
this.faceMap = faceList.stream().collect(Collectors.toMap(faceInterface -> faceInterface.getCode().name(), Function.identity()));
this.armsMap = armsList.stream().collect(Collectors.toMap(armsInterface -> armsInterface.getCode().name(), Function.identity()));
this.mobilityMap = mobilityList.stream().collect(Collectors.toMap(mobilityInterface -> mobilityInterface.getCode().name(), Function.identity()));
this.materialMap = materialList.stream().collect(Collectors.toMap(materialInterface -> materialInterface.getCode().name(), Function.identity()));
this.robotComponentStock = robotComponentStock;
}
public boolean validateStockAvailability(RobotComponent robotComponent){
String face = robotComponent.getFace();
String arms = robotComponent.getArms();
String mobility = robotComponent.getMobility();
String material = robotComponent.getMaterial();
Code faceCode = faceMap.get(face).getCode();
Code armsCode = armsMap.get(arms).getCode();
Code mobilityCode = mobilityMap.get(mobility).getCode();
Code materialCode = materialMap.get(material).getCode();
if (robotComponentStock.getQuantity(faceCode)<1 ...{
...
return false;
}
return true;
}
}
FaceInterface、ArmsInterface、MobilityInterface、MaterialInterface 是具有不同实现的接口。
我尝试了什么:
@MockBean
private RobotComponentStock robotComponentStock;
@MockBean
private List<FaceInterface> faceInterfaceList;
@MockBean
private List<MobilityInterface> mobilityInterfaceList;
@MockBean
private List<ArmsInterface> armsInterfaceList;
@MockBean
private List<MaterialInterface> materialInterfaceList;
@InjectMocks
private ComponentInputValidator componentInputValidator;
出现错误: org.mockito.exceptions.misusing.InjectMocksException: 无法实例化类型为 'class com.demo.robot_factory.service.ComponentInputValidator' 的名为 'componentInputValidator' 的 @InjectMocks 字段。 您没有在字段声明中提供实例,所以我尝试构建实例。 但是构造函数或初始化块抛出异常:null 对于行
faceList.stream().collect(Collectors.toMap(faceInterface -> faceInterface.getCode().name(), Function.identity()));
您在测试中混合了两个不同的概念。
@MockBean
是 集成测试 中使用的 Spring 注释。它将创建一个模拟,Spring 的正常注入机制会将其注入到您的 Bean 中。
另一方面,@InjectMock
是 单元测试 中使用的来自 Mockito 的注释。
我可以就以下主题推荐此博客 Post: @Mock vs. @MockBean When Testing Spring Boot Applications
如果您想编写单元测试,我建议将所有 @MockBean
注释替换为 Mockitos @Mock
。
// same for the other dependencies you want to mock
@Mock
private List<MaterialInterface> materialInterfaceList;
@InjectMocks
private ComponentInputValidator componentInputValidator;
这应该可以修复异常。
查看您的代码,我建议您采用完全不同的测试方法。
我不明白你为什么要首先模拟列表。您不能只实例化列表并手动构建 ComponentInputValidator
吗?例如:
@Test
void test(){
List<MaterialInterface> materialList = List.of(...)
//initialize your other dependencies here
//pass all Lists into the constructor
var validator = new ComponentInputValidator(materialList,...)
//make your assertions on the validator
}