如何在某些Spring测试中注入特定的类实例?

时间:2018-04-12 11:27:36

标签: java spring unit-testing dependency-injection

我有一个Spring组件,它将Clock作为依赖项:

@Component
public class MyClass {
    private final Clock clock;

    @Autowired
    public MyClass(Clock clock){
        this.clock = clock
    }
}

对于我的大多数测试,我有一个模拟时钟,注释为@Bean并正确注入。但是,对于我的一些测试,我需要使用不同的模拟时钟。如何在这些测试中使用不同的模拟?

public class MyClassTest {

    @Autowired
    private MyClass myClass;

    @Test
    public void test1(){
         // use the standard mock clock
    }

    @Test
    public void test2(){
         // inject clock.fixed(Instant.parse("2018-01-01T00:00:00Z"), UTC);
    }


    @Test
    public void test3(){
         // inject clock.fixed(Instant.parse("2019-12-12T23:59:59Z"), UTC);
    }
}

因此,在此示例中,我想覆盖test2test3中的模拟时钟。

3 个答案:

答案 0 :(得分:0)

您可以使用ReflectionTestUtils注入各种模拟。它是为此目的而制作的。

@Test
public void test2(){
     // inject clock.fixed(Instant.parse("2018-01-01T00:00:00Z"), UTC);
     ReflectionTestUtils.setField(myClass, "clock", mockClock);
}

答案 1 :(得分:0)

我认为处理这种用例的正确方法是使用只有一个bean的Mockito lib,只需按需更改存根方法实现:

Worker

Mockito已经由spring-boot-starter-test提供。

答案 2 :(得分:0)

让我们看看你拥有的所有选项。

手动替换依赖

就像在其他答案中建议的那样,如果字段是私有的或者创建了一个setter,则可以使用ReflectionTestUtils。这是一个简单的方法,但它有一些你应该注意的缺点。

如果MyClass调用其他类OtherClockClient,那么它也使用时钟,类不知道这样的替换,你可能会出现不一致,因为两个时钟就在附近。

另一个问题是手动更换会破坏弹簧环境。这很重要,因为默认情况下在测试之间重用spring上下文,并且不保证测试顺序。这意味着可能会在test2之前执行test1并且test1中不会使用“标准”时钟。如果test1依赖于隐式设置“标准”时钟的行为,则会遇到麻烦。

要解决此问题,您可以使用@DirtiesContext标记测试,也可以手动还原依赖项。

单一调度员

您始终可以在测试中注入相同的时钟,默认情况下,它应该演示您命名为“standard”的行为。但是,它可以提供额外的API,允许测试根据需要配置时钟。

public class ConfigurableClock implements Clock {
    void fixAt(Instant instant) {
    }
}

public class MyClassTest {

  @Autowired
  private ConfigurableClock clock;

  @Test
  public void test1() {
    // use standard clock behaviour
  }

  @Test
  public void test2(){
     clock.fixAt(Instant.parse("2018-01-01T00:00:00Z"));
  } 

在这种情况下,不需要重新连接bean,但仍应重置状态,以便期望隐式默认时钟的测试具有它。您可以使用@Before / @After方法重置时钟:

@Before
public setUp() {
   clock.reset();
}

@After
public tearDown() {
   clock.reset();
}

或添加TestExecutionListener即可。