@InjectMocks 通过 Constructor 注入 @MockBean 并且 setter 无法正常工作

@InjectMocks inject @MockBean by Constructor and setter not working properly

我试了很多次不唱@RunWith(SpringJUnit4ClassRunner.class) 我试图用 getter 和构造函数注入创建一个针对 class 的测试用例。当我使用 @MockBean 进行 setter 注入时,@Mock 进行构造函数注入并且还使用 @RunWith(SpringJUnit4ClassRunner.class)MockitoAnnotations.initMocks(this); bean 注入。 如果我评论 MockitoAnnotations.initMocks(this); 构造函数注入不起作用。 现在所有的 bean 都被完美地注入了,但是 @Mock beans(构造函数注入)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;
}
}

我的测试 Class 是

@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 但是mockA.getValue() return 当我测试 运行.

时正确

当您 运行 使用 spring 运行ner 进行测试时,您必须指定您希望将什么作为 bean 加载(阅读,让 spring 知道什么完全应该包含在应用程序上下文中)。

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

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

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

在这种情况下,没有必要调用 MockitoAnnotations.initMocks(this); Spring 将在所有配置正确后自行注入模拟。

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

请参考spring开机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 
}
}

解决方案:

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

Normal bean initialize methods like SpringJUnit4ClassRunner or MockitoAnnotations.initMocks(this); handling only one type injection at a time. Either constructor or Auto wired injection.

@RunWith(SpringJUnit4ClassRunner.class) 表示 public class SpringJUnit4Class运行ner 扩展了 BlockJUnit4Class运行ner。 SpringJUnit4Class运行ner 是 JUnit 的自定义扩展。它将在测试的初始时间初始化模拟 @MockeBean 和 @bean anotted beans run.Alsoi 运行nig bean 注入。

必须调用

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

的 setup() 方法

所以在上面的问题中你使用了 SpringJUnit4Class运行ner 和 MockitoAnnotations.initMocks(this);它将创建两个模拟 bean 引用,您可以为它们使用 @Mock。同样在上面的代码流程中。

1.At 开始 SpringJUnit4ClassRunner 运行 它将为 @Mock 和 @MockBean 创建 bean 引用,注释 attributes.after 它只会在 tjis 时间创建注入的 bean发生构造函数注入

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

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

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