如何让DropWizard JUnit应用程序规则定义使用docker规则中的启动信息?

时间:2018-03-22 21:05:49

标签: java docker junit dropwizard

我想解决的一般问题是这个。我有一个解决方案,但它非常笨重,而且我希望有人知道一个更有序的解决方案。

Dropwizard提供了一个名为DropwizardAppRule的JUnit TestRule,用于集成测试。你这样使用它:

@ClassRule
public static final DropWizardAppRule<MyConfiguration> APP_RULE = new DropwizardAppRule(MyApplication.class, myYmlResourceFilePath, ConfigOverride("mydatabase.url", myJdbcUrl));

它将启动您的应用程序,使用您的yml资源文件配置它,并使用您在构造函数中指定的替代。但请注意,您的覆盖在施工时受到约束。

还有JUnit规则来启动Docker容器,我使用一个来启动MySql,还有一个JUnit RuleChain来强制在启动Dropwizard应用程序之前容器必须启动的事实这取决于它。

如果我愿意事先指定希望MySql容器公开的端口,那么这一切都很有效。我不是。我希望这些集成测试能够在构建机器上运行,很可能并行地用于同一项目的分支构建,我更倾向于使用您要求Docker选择任何可用端口的机制,并使用它。

我遇到的问题是,在构建DropwizardAppRule时,暴露的容器端口是未知的,这是唯一可以绑定配置覆盖的时间。

我采用的解决方案是制作包装器JUnit Rule,如下所示:

public class CreateWhenRunRuleWrapper<T extends ExternalResource> extends ExternalResource {
    private final Supplier<T> wrappedRuleFactory;
    private T wrappedRule;

    public CreateWhenRunRuleWrapper(Supplier<T> wrappedRuleFactory) {
        this.wrappedRuleFactory = wrappedRuleFactory;
    }

    public T getWrappedRule() {
        return wrappedRule;
    }

    @Override
    protected void before() throws Throwable {
        wrappedRule = wrappedRuleFactory.get();
        wrappedRule.before();
    }

    @Override
    protected void after() {
        wrappedRule.after();
    }
}

这很有用,允许我在before()方法中构造DropWizardAppRule类,但显然不在JUnit的设计意图之内,因为我必须在org.junit中找到它。规则包,以使我的类能够调用后期创建的规则的before()和after()方法。

实现同一目标的更有条理,最佳实践方式是什么?

1 个答案:

答案 0 :(得分:0)

我们提出的2个选项:

hacky解决方案是使用static {},它在启动容器之后但在初始化dropwizard实例之前执行代码:

public static final GenericContainer mongodb = new GenericContainer("mongo:latest").withExposedPorts(27017);
static {
    mongodb.start();
    System.setProperty("dw.mongoConfig.uri", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getMappedPort(27017));
}

@ClassRule
public static final DropwizardIntegrationAppRule<Config> app1 = new DropwizardIntegrationAppRule<>(Service.class);

第二种选择更清洁,更像你的选择。

private static final MongoDContainerRule mongo = new MongoDContainerRule();

private static final DropwizardIntegrationAppRule<Config> app = new DropwizardIntegrationAppRule<>(Service.class);

@ClassRule
public static final RuleChain chain = RuleChain
        .outerRule(mongo)
        .around(app)

MongoDContainerRule就像你的包装器,但它也通过系统属性设置了正确的端口。

public class MongoDContainerRule extends MongoDBContainerBase {

    private static final GenericContainer mongodb = new GenericContainer("mongo:latest").withExposedPorts(27017);

    @Override
    protected void before() throws Throwable {
        mongodb.start();
        System.setProperty("dw.mongoConfig.uri", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getMappedPort(27017));
        System.setProperty("dw.mongoConfig.tls", "false");
        System.setProperty("dw.mongoConfig.dbName", DB_NAME);
    }

    @Override
    protected void after() {
        mongodb.stop();
    }
}

容器会在自由端口上暴露mongodb。 mongodb.getMappedPort(internalPort)将返回它。 System.setProperty(“dw。*”)将值注入dropwizard配置。