Общая проблема, которую я пытаюсь решить, заключается в следующем. У меня есть решение, но оно очень неуклюже, и я надеюсь, что кто-то знает более упорядоченное решение.
Dropwizard предлагает JUnit TestRule под названием DropwizardAppRule, которое используется для интеграционных тестов. Вы используете это так:
@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-оболочки, например:
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();
}
}
Это работает, позволяя мне создать класс DropWizardAppRule в методе before (), но совершенно очевидно, что он выходит за рамки проектного замысла JUnit, о чем свидетельствует тот факт, что мне пришлось разместить его в пакете org.junit.rules, чтобы расширить возможности мой класс, чтобы иметь возможность вызывать методы before () и after () поздно созданного правила.
Что было бы более упорядоченным и передовым способом достижения той же цели?




2 варианта, которые мы придумали:
Хакерское решение - использовать 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.