При настройке CI/CD часто надо запускать на различных окружениях: qa, dev, продакшене, uat. Зачастую различные креды, ссылки, порты и коннекшены к базе данных отличаются. Можно через кучу if/else в зависимости от окружения использовать нужные данные, но это, мягко говоря, не самая лучшая идея.
Так как эта информация редко когда меняется в тестах, то есть смысл держать где-то обособленно. Как вариант, можно использовать property – файл для каждого окружения, вот один из примеров:
1 2 3 4 5 6 7 8 9 10 |
# данные приложения url=http://yoururl.com username=login password=superpassword # данные базы данных db.hostname=db.yoururl.com db.port=3308 db.username=db_admin db.password=secured! |
Для получения доступа к данным могу посоветовать одну хорошую библиотеку. В Maven необходимо подключить следующие зависимости:
1 2 3 4 5 |
<dependency> <groupId>org.aeonbits.owner</groupId> <artifactId>owner</artifactId> <version>1.0.8</version> </dependency> |
Далее создаём простой интерфейс:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Sources({ "classpath:qa.properties" // указываем имя property - файла }) public interface Environment extends Config { String url(); String username(); String password(); @Key("db.hostname") String getDBHostname(); @Key("db.port") int getDBPort(); @Key("db.username") String getDBUsername(); @Key("db.password") String getDBPassword(); } |
Тут есть две особенности:
- Если имя метода схоже с ключом в проперти – файле, то достаточно вызвать метод;
- Если они не совпадают, то матчим с помощью @Key.
С помощью ConfigFactory мы объединяем интерфейс с нашим файлом:
1 2 3 |
Environment testEnvironment = ConfigFactory.create(Environment.class); System.out.println(testEnvironment.url()); System.out.println(testEnvironment.getDBHostname()); |
Дальше в тестах или пэйджах мы спокойно можем работать с данными, для этого необходимо только создать объект класса Environment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class EnvironmentTest { Environment testEnvironment; @Test public void functionalTest() { System.out.println(testEnvironment.url()); System.out.println(testEnvironment.getDBHostname()); System.out.println(testEnvironment.getDBPassword()); } @BeforeTest public void beforeTest() { testEnvironment = ConfigFactory.create(Environment.class); } } |
Чтобы не хардкодить название окружение, а получать его динамически, можно в примере интерфейса изменить немного @Sources:
1 2 3 |
@Sources({ "classpath:${env}.properties" }) |
Теперь нам дана возможность выбирать конкретное окружение в сьютах:
1 2 3 4 |
<suite name="My Suite"> <parameter name="environment" value="production"/> <test name="Simple test"> <-- ... --> |
Если вам этого мало, то можете с помощью TestNG передавать через параметры:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class EnvironmentTest { Environment testEnvironment; @Test public void functionalTest() { System.out.println(testEnvironment.url()); System.out.println(testEnvironment.getDBHostname()); System.out.println(testEnvironment.getDBPassword()); } @BeforeTest @Parameters({"environment"}) public void beforeTest(String environemnt) { ConfigFactory.setProperty("env", environemnt); testEnvironment = ConfigFactory.create(Environment.class); } } |
Как видим не всё так страшно, как казалось. Без изменения кода и нагромождения ненужной логики мы легко можем управлять данными, специфичными для каждого конкретного окружения.