В моей предыдущей статье мы говорили об основных концепциях тестирования API в Java с использованием HTTPs-соединений. Мы выяснили как создается хранилище доверенных сертификатов (trust store), содержащее сертификат, возвращаемый нашим тестовым сервисом. Таким образом, мы научились избегать ошибок вида "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". Теперь мы взглянем на более оформленное решение, которое будет включать в себя использование таких фреймворков как Maven и JUnit5. Ключевая проблема, которую мы будем решать - это добавление нашего trust store в структуру проекта, так чтобы тесты всегда использовали бы одно и то же хранилище, где бы они не запускались.
Описание примера: простой Мавен-проект с API-тестами, работающими по HTTPs-протоколу
Мы взглянем на пример, который очень похож на то, что я использовал в своей предыдущей статье. Но на этот раз мы создадим корректно стилизованный тестовый проект, который будет использовать Maven и JUnit вместо простого запуска всего в main
-методе. Итак, наш pom.xml
будет выглядеть так:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>click.webelement</groupId> <artifactId>ssl-api-tests</artifactId> <version>1.0-SNAPSHOT</version> <properties> <java.version>1.8</java.version> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.5.2</version> <scope>test</scope> </dependency> </dependencies> </project>
А вот как будет выглядеть наш тестовый класс:
package click.webelement.https; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; public class ApiWithSSLTest { private final static int OK_CODE = 200; @Test public void callHttpsEndpoint() throws IOException { HttpURLConnection connection = (HttpURLConnection) new URL("https://webelement.click").openConnection(); Assertions.assertEquals(OK_CODE, connection.getResponseCode(), "Response code should be successful"); } }
Так как мы собираемся сконцентрироваться на том как добавить доверенное хранилище в тестовый проект, а не на том, как создать такое хранилище, я предполагаю, что вы уже его подготовили. Если нет, добро пожаловать в мою предыдущую статью, где я описываю необходимые шаги.
Добавляем доверенное хранилище сертификатов в Maven-проект
Первое, что необходимо сделать - это положить файл хранилища в папку resources
вашего Maven-проекта (так как мы говорим о тестировании, и скоуп депенденси JUnit - test
, мы будем хранить весь код и ресурсы в папке src/test
). Теперь нам надо получить путь к нашему хранилищу. Этот путь может быть разным в разных средах, однако существует способ получить текущий путь к любому ресурсу вашего проекта в рантайме, используя следующий подход.
Получить URI ресурса:
URI trustStoreURI = ApiWithSSLTest.class.getClassLoader().getResource(TRUST_STORE_FILE).toURI();
Транслировать полученный URI в путь к файлу:
String trustStoreFilePath = new File(trustStoreURI).getAbsolutePath();
Таким образом, совместив эти шаги и добавив их в код, мы получим следующий тестовый класс:
package click.webelement.https; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; public class ApiWithSSLTest { private final static String TRUST_STORE_FILE = "mytruststore"; private final static String TRUST_STORE_PASSWORD = "mystorepass"; private final static int OK_CODE = 200; @BeforeAll public static void setUpAll() throws URISyntaxException { URI trustStoreURI = ApiWithSSLTest.class.getClassLoader().getResource(TRUST_STORE_FILE).toURI(); System.setProperty("javax.net.ssl.trustStore", new File(trustStoreURI).getAbsolutePath()); System.setProperty("javax.net.ssl.trustStorePassword", TRUST_STORE_PASSWORD); } @Test public void callHttpsEndpoint() throws IOException { HttpURLConnection connection = (HttpURLConnection) new URL("https://webelement.click").openConnection(); Assertions.assertEquals(OK_CODE, connection.getResponseCode(), "Response code should be successful"); } }
Теперь наш тест привязан к тому хранилищу сертификатов, которое находится в файле src/test/resources/mytruststore
. Это означает, что, будучи частью CI пайплайна код ваших тестов скомпилируется вместе с вложенным в ресурсы хранилищем, после чего в рантайме настроится на это хранилище независимо от того в какой среде, процесс будет исполняться.
Если после прочтения у вас всё ещё остались вопросы, присылайте их мне используя эту форму обратной связи. Я постараюсь ответить вам напрямую, а также скорректировать статью, опираясь на ваши отзывы.