@InjectMocks通过构造方法和设置方法注入@MockBean不能正常工作

时间:2019-11-07 04:54:05

标签: java dependency-injection mockito junit4 springmockito

我通过取消唱歌@RunWith(SpringJUnit4ClassRunner.class)尝试了很多次 我试图用getter和Constructor注入创建一个测试用例。当我将@MockBean用于setter注入时,将@Mock用于构造函数注入,并且还将@RunWith(SpringJUnit4ClassRunner.class)MockitoAnnotations.initMocks(this); Bean注入使用。  如果我评论MockitoAnnotations.initMocks(this);构造函数注入无效。 现在所有的bean都被完美地注入了,但是@Mock bean(注入了Contructor)bean嘲笑了它们在调用时无法正常工作。

@Component
Class A{
}

@Component
Class B {
}

@Component
Class c{
}

@Component
Class D{
@Atowired
A a;

B b;
C c;
@Autowired
public D(B b,C c){
b=b;
c=c;
}
}

我的测试班是

@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@Mock
B mockB
@Mock
C mockC
@InjectMocks
D mockD

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");

}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before 
}
}

注入工作正常,问题属于我使用的bean的模拟方法@Mock工作不正常意味着mockB.getValue()mockC.getValue()重新调整null但{{ 1}}在我测试运行时正确返回。

3 个答案:

答案 0 :(得分:2)

如果您正在使用SpringJUnit4ClassRunner.class运行测试,则需要使用@MockBean而不是@Mock

请参阅弹簧靴documentation

此外,您需要使用@Autowired而不是@InjectMocks

@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@MockBean
B mockB
@MockBean
C mockC
@Autowired
D mockD

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");

}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before 
}
}

答案 1 :(得分:1)

使用springRunner运行测试时,必须指定要作为bean加载的确切内容(阅读,让spring知道应将什么内容确切地包含在应用程序上下文中。)

通常可以使用@ContextConfiguration批注来完成。

我怀疑由于您未指定此注释,因此spring不会真正加载任何组件(问题中的A,B,C等)。

现在@MockBean基本上允许出于测试目的“更改”应用程序上下文。为此,它提供了一个模拟文件,而不是应在“常规”应用程序上下文中加载的真实bean。

在这种情况下,没有必要调用MockitoAnnotations.initMocks(this);,只要一切配置正确,Spring就会自己注入模拟。

答案 2 :(得分:1)

  

普通的bean初始化方法,例如SpringJUnit4ClassRunnerMockitoAnnotations.initMocks(this);一次只能处理一种类型的注入。构造函数或自动有线注入。

@RunWith(SpringJUnit4ClassRunner.class) 表示公共类SpringJUnit4ClassRunner扩展了BlockJUnit4ClassRunner。 SpringJUnit4ClassRunner是JUnit的自定义扩展。它将在测试运行的初始时刻初始化模拟@MockeBean和@bean的豆。Alsoi也会运行bean注入。

必须调用

MockitoAnnotations.initMocks(this)方法来初始化带注释的字段。在上面的示例中,在测试的基类的@Before(JUnit4)方法中调用了initMocks()。对于JUnit3,initMocks()可以转到基类的setup()方法。

因此,在上述问题中,您使用了SpringJUnit4ClassRunner和MockitoAnnotations.initMocks(this);它将创建两个您可以使用@Mock的模拟bean引用。同样在上述代码流中。

1。在SpringJUnit4ClassRunner开始运行时,它将为@Mock和@MockBean带注释的属性创建bean引用。此后,它将在tjis时间创建注入的bean,仅在构造函数注入时发生

2.Run @Before and Run MockitoAnnotations.initMocks(this);,它将为@Mock注释属性创建另一个模拟引用,并仅替换直接引用。和自动有线注入此时运行。

  1. 运行MockitoAnnotations.initMocks(this);之后,您将看到allk bean已初始化并注入良好。但是通过构造函数注入的bean不是正确的引用,而是引用由SpringJUnit4ClassRunner创建的旧bean引用。

如果要为单个bean实现构造函数和自动有线注入,则必须对构造函数注入使用手动bean注入。您可以参考here

解决方案:

@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@MockBean
B mockB
@MockBean
C mockC
@Autowired
D mockD

@Before
public void setUp() {
mockD = new D(mockA,mockB);
MockitoAnnotations.initMocks(this);
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");

}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before 
}
}