Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring Mockito注入不能同时用于构造函数和setter mock_Spring_Constructor_Code Injection_Mockito_Setter - Fatal编程技术网

Spring Mockito注入不能同时用于构造函数和setter mock

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

我有一个类,通过构造函数注入成员,通过setter注入其他成员。我似乎无法让莫基托注射二传者。注入的构造函数被模拟得很好,但setter返回为null。当我将setter-ed成员转换为构造函数注入时,一切都很好。以下是原始生产代码:

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