我通过取消唱歌@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}}在我测试运行时正确返回。
答案 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初始化方法,例如
SpringJUnit4ClassRunner
或MockitoAnnotations.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注释属性创建另一个模拟引用,并仅替换直接引用。和自动有线注入此时运行。
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
}
}