简体   繁体   English

在带有Mockito的单元测试中使用带有@Required字段的类

[英]Using a Class with a @Required Field in Unit Test with Mockito

I'm trying to unit test a class; 我正在尝试对课程进行单元测试; for the sake of brevity we'll call it Apple. 为了简洁起见,我们将其称为Apple。 It has a @Required setter that takes an AppleManager bean. 它具有使用AppleManager bean的@Required setter。 AppleManager itself has a @Required setter than takes an AppleStorageClient bean. AppleManager本身具有@Required设置程序,而不是AppleStorageClient bean。 I am mocking AppleManager and injecting it into Apple, but I also need to use the real AppleManager class to retrieve data using methods from its AppleStorageClient object. 我正在模拟AppleManager并将其注入到Apple中,但是我还需要使用真正的 AppleManager类通过其AppleStorageClient对象中的方法来检索数据。 How can I achieve this with Spring/Mockito? 如何使用Spring / Mockito实现此目的?

Test: 测试:

public class AppleTest {

   @InjectMocks
   private Apple apple;

   @Mock
   private AppleManager appleManager;

   ????? 
   private AppleManager realAppleManager;
   //I tried = new AppleManager() here but the object is null...
   //ostensibly because Spring doesn't know I want to use the bean
   //also tried @Autowired to no avail

   @Before
   public void doBeforeStuff() {
      MockitoAnnotations.initMocks(this);
   }

   ...
}

Source: 资源:

public class Apple {

   private AppleManager appleManager;

   @Required
   public void setAppleManager(AppleManager appleManager) {
      this.appleManager = appleManager;
   }

   ....

}

&

public class AppleManager {

    private AppleStorageClient appleStorageClient;

       @Required
       public void setAppleStorageClient() {
          this.appleStorageClient = appleStorageClient;
       }

       ...

    }

In general it looks like something is 'uncomplete' here. 总的来说,这里看起来有些“不完整”。 I'll explain why. 我会解释原因。

Technically If you're using spring - it doesn't sound like a unit test to me anymore, probably integration test or something. 从技术上讲,如果您使用的是Spring,对我而言,这听起来不再像是单元测试,可能不是集成测试。 Unit tests are in general should be really-really fast and starting up spring won't let them pass fast enough (think about having thousands of unit tests in your project each of them running spring on startup - it will take them ages to complete). 一般而言,单元测试应该确实非常快,并且春季启动不会让它们通过得足够快(考虑一下,在您的项目中有成千上万的单元测试,每个项目在启动时都会在春季运行-需要花一些时间才能完成) 。

But let's say its only about definitions. 但是,仅说它与定义有关。 When you're using spring testing framework with JUnit, someone has to start and maintain a spring context to do all the Dependency Injection magic and apply it to the test case. 当您将弹簧测试框架与JUnit一起使用时,必须有人启动并维护一个弹簧上下文,以完成所有的Dependency Injection魔术并将其应用于测试用例。 In Junit implementation a special Runner (a JUnit abstraction) is required: 在Junit实现中,需要特殊的Runner(JUnit抽象):

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:my-test-context.xml" }) // or use Java Config

This doesn't appear in the question though. 虽然这没有出现在问题中。

So now Spring will create a context and will attempt to inject beans. 因此,现在Spring 创建一个上下文并尝试注入bean。 And we have effectively reduced our issue to the issue of having two implementations of the interface and asking spring to inject implementation by interface so that two different implementations will be injected. 并且我们已经有效地将问题简化为具有接口的两个实现,并要求spring通过接口注入实现,以便注入两个不同的实现。 There are 2 solutions I can see here: 我可以在这里看到2种解决方案:

  1. Create a Mock outside spring - you probably won't specify your expectations in spring anyway. 在春季以外创建一个模拟对象-无论如何您可能都不会在春季指定期望。 Maintain only a "real apple manager" in spring 春季只维持一个“真正的苹果经理”

  2. Maintain both in spring but in your test case use a @Qualifier annotation 在春季维护两者,但在测试用例中使用@Qualifier批注

Now what I would like to emphasize is that if you maintain real apple manager that contacts "apple store" (probably a database, with driver support, transaction management and so forth) you'll have to create a test context so that it will be able to connect to that database, and if the apple manager internally injects its dependencies via spring, then these beans are also have to be specified. 现在,我要强调的是,如果您维护与“苹果商店”(可能是数据库,具有驱动程序支持,事务管理等)联系的真正的苹果管理器,则必须创建一个测试上下文,以便能够连接到该数据库,并且如果apple manager通过spring在内部注入其依赖项,那么还必须指定这些bean。

So that if in future you'll change something in the underlying store (say, add a dependency in a driver to another spring bean, this test context will automatically become broken). 这样一来,如果将来您将在基础存储中进行某些更改(例如,将驱动程序中的依赖项添加到另一个spring bean中,则该测试上下文将自动失效)。 Just be aware of this and inject beans wisely. 请注意这一点,并明智地注入豆类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM