我正在使用springockito-annotations 1.0.9
进行集成测试。
我有以下控制器:
@Autowired
public Controller(
@Qualifier("passwordService ") PasswordService passwordService ,
@Qualifier("validator") Validator validator,
@Qualifier("reportService") ReportService reportService,
DateCalculator dateCalculator,
Accessor accessor){
this.passwordService = passwordService;
this.validator = validator;
this.reportService = reportService;
this.dateCalculator = dateCalculator;
this.accessor = accessor;
}
在测试中,我将使用 @ReplaceWithMock 注释从上下文中替换bean。
但不幸的是,它仅适用于依赖 whithout @Qualifier 注释。
即,我的测试看起来像这样:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(loader = SpringockitoAnnotatedContextLoader.class, classes = {TestContext.class})
public class ControllerTest {
@Autowired
@ReplaceWithMock
private PasswordService passwordService ;
@Autowired
@ReplaceWithMock
private Validator validator;
@Autowired
@ReplaceWithMock
private ReportService reportService;
@Autowired
@ReplaceWithMock
private DateCalculator dateCalculator;
@Autowired
@ReplaceWithMock
private Accessor accessor;
@Autowired
private Controller controller;
}
在初始化上下文后的最后一种情况下, DateCalculator和Accessor bean正确替换了所需的模拟,但另一个bean自动装配为主要上下文中的普通bean 。
调试后我发现 QualifierAnnotationAutowireCandidateResolver 无法正确识别bean。在下面的行中,从 229 :
开始RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
Spring试图从模拟依赖中提取限定符,但它是空的。
很高兴知道如何正确地将@Qualifier的依赖替换为模拟对象。
答案 0 :(得分:2)
编辑添加了指向whitebox替代品的链接,它在Mockito的更高版本中消失了
可以使用mockitos @Mock
和@InjectMocks
将您想要测试的内容注入到您的课程中,如其他帖子所示。我曾经认为这是测试Spring托管bean的好方法,但现在我觉得它有问题;如果
由@InjectMocks
完成的注射失败,它会默默地执行,您不知道为什么。在创建测试时,它可以是可管理的,但是当您进行这样的测试时,由于无意识的小故障,几个测试开始因为无效指针而失败
更改为某人制作的应用程序上下文,或者在引入次要异常或类似的合并之后,它会变得比它需要的更加混乱。
我建议您使用mockitos Whitebox
,请参阅下面的示例。有了它,你可以明确告诉你想要的字段"注入"什么对象,在复杂的情况下,你可以注入多个对象。 Mockito在注入时使用Whitebox(但吞下所有例外)。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration( /*something that fits your setup*/ )
public class ControllerTest {
@Autowired
private PasswordService passwordService ;
@Autowired
private Validator validator;
@Autowired
private ReportService reportService;
@Autowired
private Controller testObject;
@Before
public void setupBefore() {
//Since this "injection" is done manually the qualifiers does not matter
Whitebox.setInternalState(testObject, "passwordService", passwordService);
Whitebox.setInternalState(testObject, "validator", validator);
Whitebox.setInternalState(testObject, "reportService", reportService);
}
@Test
public void testSomething() {
}
}
如果您正在进行常规单元测试,Whitebox
可以帮助您在没有弹簧环境的情况下进行测试。我强烈推荐这种方法(但它有点偏离主题,我不会发布我写的例子,之前我注意到你正在进行集成测试;))。
编辑:如果您使用的是Mockito的更高版本,您会注意到Whitebox已经消失,那么该怎么做呢? 我遇到了这种情况,并征求意见:What do I use instead of Whitebox in Mockito 2.2 to set fields?
答案 1 :(得分:1)
您不再需要这样做了。 Mockito本身从版本1.8.3开始,现在支持带注释的模拟和模拟注入,如下所述:http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Mockito.html#21
我们现在进行以下单元测试:
// No annotation required
public class SomeTest {
@Mock
private SomeDependency someDependency;
@Mock
private SomeDependency2 someDependency2;
@InjectMocks
private ClassUnderTest classUnderTest;
@BeforeMethod(alwaysRun = true)
public void setUp() {
MockitoAnnotations.initMocks(this);
}
public void testSomething() {
// Do your Mockito test here.
}
}