【问题标题】:Using a Class with a @Required Field in Unit Test with Mockito在 Mockito 的单元测试中使用带有 @Required 字段的类
【发布时间】:2017-04-13 00:58:58
【问题描述】:

我正在尝试对一个类进行单元测试;为简洁起见,我们将其称为 Apple。它有一个带有 AppleManager bean 的 @Required 设置器。 AppleManager 本身有一个 @Required 设置器,而不是一个 AppleStorageClient bean。我正在模拟 AppleManager 并将其注入 Apple,但我还需要使用 real AppleManager 类来使用其 AppleStorageClient 对象中的方法检索数据。如何使用 Spring/Mockito 实现这一目标?

测试:

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);
   }

   ...
}

来源:

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

       ...

    }

【问题讨论】:

    标签: java spring unit-testing junit mockito


    【解决方案1】:

    一般来说,这里看起来有些“不完整”。我会解释原因。

    从技术上讲,如果您使用的是 spring - 它对我来说不再像是单元测试,可能是集成测试之类的。 单元测试通常应该非常非常快,并且启动 spring 不会让它们足够快地通过(考虑在您的项目中有数千个单元测试,每个测试都在启动时运行 spring - 这需要他们很长时间才能完成) .

    但是让我们说它只是关于定义。当您在 JUnit 中使用 spring 测试框架时,必须有人启动并维护一个 spring 上下文来执行所有依赖注入魔法并将其应用于测试用例。 在 Junit 实现中,需要一个特殊的 Runner(一个 JUnit 抽象):

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

    这并没有出现在问题中。

    所以现在 Spring 创建一个上下文并尝试注入 bean。我们已经有效地将我们的问题简化为拥有两个接口实现并要求spring按接口注入实现的问题,以便注入两个不同的实现。我可以在这里看到 2 个解决方案:

    1. 在 spring 之外创建一个 Mock - 你可能不会在 spring 中指定你的期望。春季只维持一个“真正的苹果经理”

    2. 在 spring 中同时维护,但在您的测试用例中使用 @Qualifier 注释

    现在我想强调的是,如果您维护与“苹果商店”联系的真正的苹果管理器(可能是一个数据库,具有驱动程序支持、事务管理等),您将必须创建一个测试上下文,以便它将能够连接到该数据库,并且如果苹果管理器通过 spring 在内部注入其依赖项,那么这些 bean 也必须指定。

    因此,如果将来您要更改底层存储中的某些内容(例如,将驱动程序中的依赖项添加到另一个 Spring bean,此测试上下文将自动损坏)。请注意这一点并明智地注入 bean。

    【讨论】:

    • 谢谢,马克!我在提供上下文的测试类的超类中确实有一个 ContextConfig,但我发现它缺少定义 AppleStorageClient bean 的 .xml。话虽如此,根据您的解释,对我来说,重新设计当前的“测试”实现似乎更有意义,所以我会试一试。
    • @Mark Bramnik:Spring 上下文只会加载一次,只要您使用相同的上下文并且不使用 DirtiesContext 注释即可。也许还有其他一些限制 (docs.spring.io/spring/docs/current/spring-framework-reference/…)
    猜你喜欢
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多