Spring Mockito注入不能同时用于构造函数和setter mock
我有一个类,通过构造函数注入成员,通过setter注入其他成员。我似乎无法让莫基托注射二传者。注入的构造函数被模拟得很好,但setter返回为null。当我将setter-ed成员转换为构造函数注入时,一切都很好。以下是原始生产代码:Spring Mockito注入不能同时用于构造函数和setter mock,spring,constructor,code-injection,mockito,setter,Spring,Constructor,Code Injection,Mockito,Setter,我有一个类,通过构造函数注入成员,通过setter注入其他成员。我似乎无法让莫基托注射二传者。注入的构造函数被模拟得很好,但setter返回为null。当我将setter-ed成员转换为构造函数注入时,一切都很好。以下是原始生产代码: @Autowired private BetRepository betRepository; public void setBetRepository(BetRepository betRepository) { this.betRepository = be
@Autowired
private BetRepository betRepository;
public void setBetRepository(BetRepository betRepository) {
this.betRepository = betRepository;
}
public TournamentScoringCache(TournamentScoringCacheInitializer cacheInitializer,
ScoringEngineInitializer scoringEngineInitializer) {
tournamentUserStates = cacheInitializer.initCache();
scoringEngines = scoringEngineInitializer.initEngines();
}
public <T extends SideScore> void updateGameScore(Long tournamentId, Long gameId, MatchScore<T> score) {
Map<Long, UserTournamentState> userStates = tournamentUserStates.get(tournamentId);
ScoringEngine<?> scoringEngine = scoringEngines.get(tournamentId);
List<Bet> bets = betRepository.getBetsByGameId(gameId); //HERE IS WHERE I GET THE NPE
....
}
有什么想法吗
谢谢 是的,@InjectMocks注释使Mockito要么进行构造函数注入,要么进行setter/field注入,但决不能两者都进行。选择的规则非常复杂,这也是我尽量避免使用@InjectMock的原因之一 总之,Mockito首先从类拥有的构造函数中选择一个构造函数,然后分析该构造函数是否可用于构造函数注入。它选择的那个永远是争论最多的那个。如果有多个构造函数具有相同数量的参数,则未定义将选择哪个构造函数 如果所选构造函数的一个或多个参数的类型是基元类型、最终类或私有类,则不会使用构造函数注入。即使可以使用其他构造函数
如果未使用构造函数注入,或者如果唯一的构造函数是默认构造函数,则将使用setter/字段注入。但是setter/field注入从未与构造函数注入一起使用。这是mockito框架想要的。看这个 我发现,如果您从任何其他类扩展testclass(我创建了一个带有有意义的名称和一个小注释的空类),则可以绕过此行为
我不知道确切的原因,但我相信在扩展测试类的情况下,mockito的任何内部例程都会执行两次注入。可能是因为mockito经历了类hirachy,并且有一个内部例程,在第一次和第二次进行setter/属性注入时通过构造函数进行注入。只是猜测而已。如果我有时间,我将研究一下mockito实现。尽管强烈建议使用构造函数注入,我强烈建议不要混合注入方法,但我遇到了这样一个类,我无法重构。为了避开这个问题。例如:
@InjectMocks
private ThingWithMixedDependencies thing;
@Mock
private FieldInjected secondDependency;
@BeforeEach
void setUp() {
// This cannot be a mocked field or else it will reinitialise thing.
ConstructorInjected firstDependency = Mockito.mock(ConstructorInjected.class);
thing = new ThingWithMixedDependencies(firstDependency);
MockitoAnnotations.initMocks(this);
}
@Test
void checkDependencies() {
assertThat(thing.getFirstDependency(), is(notNullValue()));
assertThat(thing.getSecondDependency(), is(notNullValue()));
}
在这种情况下,最简单的修复方法是使用。这将注入基于构造函数的模拟以及基于setter的模拟:
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
谢谢那么如何注入setter注入的mock呢?我建议您在测试对象上显式地调用setter。不要依赖@InjectMocks来为您完成它。@Yotam您必须自己编写它。在设计良好的对象中,在使用构造函数创建对象之后,不使用setter继续对象初始化,这是不好的,一般来说,您应该始终避免可变性,因为它会破坏对象内部、容器和其他协作者。它选择的对象将始终是具有最多参数的对象。很好,谢谢。解决了我的问题。事实上,我们无法选择使用哪个构造函数真的很糟糕……但我不是mockito专家。不幸的是,@Beezer您可以向Mockito团队提出功能请求。我同意,如果有某种方法可以指定
injectmock
使用哪个构造函数,那就太好了(我认为在我写这个答案的八年左右时间里,他们没有添加它,但我不确定)。
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}