1

我已经尝试了很多次,@RunWith(SpringJUnit4ClassRunner.class) 我试图用 getter 和 Constructor 注入创建一个测试用例来对抗一个类。当我使用@MockBeansetter注入,构造@Mock函数注入以及使用bean注入时。如果我评论构造函数注入不起作用。现在所有的 bean 都被完美地注入了,但是beans(Contructor injection ) bean 在调用时模拟了 mthods 不能正常工作。@RunWith(SpringJUnit4ClassRunner.class)MockitoAnnotations.initMocks(this);MockitoAnnotations.initMocks(this);@Mock

@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()调整nullmockA.getValue()在我测试运行时正确返回。

4

3 回答 3

4

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

请参考 spring boot文档

此外,您需要使用@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 
}
}
于 2019-11-11T12:03:56.777 回答
1

当您使用 spring runner 运行测试时,您必须指定您希望作为 bean 加载的确切内容(阅读,让 spring 知道应该将哪些内容包含到应用程序上下文中)。

通常这可以通过@ContextConfiguration注释来完成。

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

现在@MockBean基本上允许“更改”应用程序上下文以用于测试目的。它通过提供一个模拟而不是应该在“常规”应用程序上下文中加载的真实 bean 来做到这一点。

MockitoAnnotations.initMocks(this);在这种情况下,一旦一切配置正确,调用 Spring 将自行注入模拟是没有意义的。

于 2019-11-07T05:08:44.240 回答
1

解决方案 :

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

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

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

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

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

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

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

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

如果要实现单个 bean 的构造函数和自动有线注入,则必须使用手动 bean 注入进行构造函数注入。你可以参考这里

于 2019-11-13T12:56:03.640 回答