Как сделать так, чтобы определение правила приложения DropWizard JUnit использовало информацию о запуске из правила докера?

Общая проблема, которую я пытаюсь решить, заключается в следующем. У меня есть решение, но оно очень неуклюже, и я надеюсь, что кто-то знает более упорядоченное решение.

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 () поздно созданного правила.

Что было бы более упорядоченным и передовым способом достижения той же цели?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
588
1

Ответы 1

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.

Другие вопросы по теме