7

我正在使用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。

但不幸的是,它仅适用于没有@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 自动装配为来自 main context 的普通 bean

调试后我发现QualifierAnnotationAutowireCandidateResolver无法正确识别 bean。在以下从229开始的行中:

RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());

Spring 试图从mocked dependency中提取限定符,但它是空的。

很高兴知道如何用@Qualifier 正确替换依赖项来模拟对象。

4

2 回答 2

2

编辑:添加了白盒替代品的链接,它在更高版本的 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 已经消失,那么该怎么做呢?我遇到了这种情况,并寻求建议:我在 Mockito 2.2 中使用什么来代替 Whitebox 来设置字段?

于 2014-11-30T18:41:24.753 回答
0

你不再需要这样做了。从版本 1.8.3 开始的 Mockito 本身现在支持注释模拟和模拟注入,如下所述: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.
  }
}
于 2014-11-16T18:36:04.587 回答