【问题标题】:@ReplaceWithMock with @Qualifier@ReplaceWithMock 与 @Qualifier
【发布时间】:2014-09-25 07:04:44
【问题描述】:

我正在使用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 自动装配为来自主上下文的普通 bean

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

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

Spring 尝试从 mocked 依赖项 中提取限定符,但它是空的。

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

【问题讨论】:

  • 在控制器类中添加“@Autowired”和“@Qualifier”可能会对您有所帮助

标签: java unit-testing spring-mvc integration-testing springockito


【解决方案1】:

编辑:添加了白盒替代品的链接,它在更高版本的 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?

【讨论】:

  • 多么强大的技术啊。上帝保佑你。
  • 非常感谢。这个答案有帮助。
  • @Sam - 如果您想升级到较新版本的 Mockito,请参阅我在答案末尾添加的链接。
【解决方案2】:

您不再需要这样做了。从 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.
  }
}

【讨论】:

    猜你喜欢
    • 2012-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    相关资源
    最近更新 更多