我有一个简单的测试案例,带有一个间谍模拟对象列表,然后我将其注入正在测试的类中
@Spy List<ValidateRule> ruleServices = new ArrayList<>();
@Mock
private EvaluateGroupType evaluateGroupType;
@Mock
private ValidateServiceRule validateServiceRule;
@InjectMocks
private ValidateRulesService validateRulesService;
@Before
public void init() throws Exception {
initMocks(this);
}
但是,在 ValidateRulesService 类中,列表被注入错误的列表。
List<Integer> demonstrationList = new ArrayList<>();
@Autowired
private List<ValidateRule> ruleServices;
我还尝试将其作为使用构造函数注入注入,这里的结果是值被注入两次
List<Integer> demonstrationList = new ArrayList<>();
final private List<ValidateRule> ruleServices;
@Autowired
public ValidateRulesService(List<ValidateRule> ruleServices) {
this.ruleServices = ruleServices;
}
我不希望 DemonstationList 在任何一种情况下都有任何值。因为它没有与 rulesService 具有相同的名称或类型,具体取决于我在@injectmocks的文档中所读到的内容。
我在这里做错了什么,或者这是Mockito的怪癖?
答案 0 :(得分:2)
这里有两件事情可做。首先,泛型在运行时不存在,所以基本上Mockito看到两个List
个实例然后应该选择一个。第二个问题是您的字段被声明为final
,Mockito在注入模拟/间谍时会跳过该字段。
使用Mockito 1.x(这是使用Spring启动1.x时的默认设置),就我所知,你无法改变这种行为,因此唯一的解决方案是自己注入字段@SetUp
方法:
private ValidateRulesService validateRulesService;
@Spy
private List<ValidateRule> ruleServices = new ArrayList<>();
@Before
public void setUp() {
// Inject the mocks/spies by yourself
validateRulesService = new ValidateRulesService(ruleServices);
}
Robert Mason's answer中也提到了这一点。
另一方面,使用Mockito 2.x,它将使用与spy / mock相同的字段名称对字段进行优先级排序,如the documentation中所示:
现场注射; mocks将首先按类型解析(如果单个类型匹配注入将发生,无论名称如何),那么,如果有多个相同类型的属性,则通过匹配字段名称和模拟名称。
还有:
注1 :如果你有相同类型(或相同的删除)的字段,最好用匹配的字段命名所有@Mock带注释的字段,否则Mockito可能会感到困惑并且注入赢了'发生了。
但是,请注意,如果您使用Mockito 2,它会在注入模拟/间谍时忽略final
个字段:
同样代表建立者或领域,他们可以通过私人可见性宣布,Mockito将通过反思看到它们。 但是,静态或最终字段将被忽略。
(强调是我自己的)
因此,如果您使用Mockito 2.x,如果您删除ruleServices
关键字,则应正确注入final
。
答案 1 :(得分:1)
我设法通过改变构造函数注入实现来正确地模拟正确的列表
测试
@Spy
List<ValidateRule> ruleServices = new ArrayList<>();
@Mock
private EvaluateGroupType evaluateGroupType;
@Mock
private ValidateServiceRule validateServiceRule;
private ValidateRulesService validateRulesService;
@Before
public void init() throws Exception {
initMocks(this);
ruleServices = Arrays.asList(evaluateGroupType, validateServiceRule);
validateRulesService = new ValidateRulesService(ruleServices);
}
正在测试的班级
private List<ValidateRule> ruleServices;
private List<ResponseTo> responseToList = new ArrayList<>();
@Autowired
public ValidateRulesService(List<ValidateRule> ruleServices) {
this.ruleServices = ruleServices;
}