微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我可以创建一个 spring bean 作为我的黄瓜步骤定义的一部分吗?

如何解决我可以创建一个 spring bean 作为我的黄瓜步骤定义的一部分吗?

在某些情况下,我的 Spring Boot 应用程序使用 LocalDate.Now() 调用提供当前日期的外部 API,并检索各种信息。我们正在使用 Cucumber 进行测试,上面在编写步骤定义时会出现问题,例如

Given external api "/some/endpoint/2021-04-21" returns csv
  | currency |
  | GBP      |

步骤定义测试代码使用 wiremock 来模拟该调用,但由于我们在生产代码中使用 LocalDate.Now(),因此测试将在 2021-04-21 以外的任何一天失败。

解决这个问题的方法是为 Clock 定义两个 bean,然后我们可以将它们自动装配到需要它们的服务中并使用 LocalDate.Now(clock)。 “真正的”bean 定义如下:

@Configuration
public class ClockConfiguration {
    @Bean
    public Clock clock() {
        return Clock.systemDefaultZone();
    }
}

测试 bean 如下所示:

@Profile("cucumber")
@TestConfiguration
public class ClockConfiguration {
    @Bean
    public Clock clock() {
        return Clock.fixed(Instant.parse("2021-02-26T10:00:00Z"),ZoneId.systemDefault());
    }
}

解决了我的问题并允许我为我的测试设置一个定义的时间,但我的问题是日期/时间是在测试配置中定义的。我想将它定义为我的步骤定义的一部分。例如像

Given Now is "2021-02-26T10:00:00Z"

一个步骤定义

@Given("Now is {string})
public void setDateTime(String dateTime) {
    //Create Clock bean here...
}

有没有办法让我做到这一点?或者甚至在黄瓜步骤中覆盖现有的 bean?

解决方法

尝试用变量或静态方法替换日期,其响应可以通过步骤定义进行更改。

@Profile("cucumber")
@TestConfiguration
public class ClockConfiguration {
    @Bean
    public Clock clock() {
        return Clock.fixed(Instant.parse(TestScope.getDateValue()),ZoneId.systemDefault());
    }
}
@Given("now is {string})
public void setDateTime(String dateTime) {
    TestScope.setDateValue(dateTime);
}

,

我设法找到了解决此问题的两种可行方法。第一个有点复杂,但我基本上创建了一个围绕 Clock 的包装类,所以一个带有方法 Clock getClock() 的接口然后有两个实现。一个是只返回 Clock.systemDefaultZone() 的真正 bean 和一个具有私有 Clock 成员的测试 bean,getter 将只返回该成员,但最重要的是像

这样的 setter
public void setClock(String dateTime) {
    this.clock = Clock.fixed(Instant.parse(dateTime),ZoneId.systemDefault());
}

然后我会通过获取 bean 来调用这个 setter 作为步骤定义方法的一部分

@Given("now is {string})
public void setDateTime(String dateTime) {
    applicationContext.getBean(MyWrapperClock.class).setClock(dateTime);
}

我发现的第二种方法要简单得多,就是在测试配置文件中简单地模拟时钟,例如

@Bean 
public Clock clock() {
    return Mockito.mock(Clock.class);
}

然后将其自动连接到步骤定义类中,然后执行一个普通的模拟 when,例如

@Given("now is {string})
public void setDateTime(String dateTime) {
    when(this.clock.instant()).thenReturn(Instant.parse(dateTime));
    when(this.clock.getZone()).thenReturn(ZoneId.systemDefault());
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。