Ayrılmış Repolarla Mobil Otomasyon

Bakican Boydaş
TurkNet Technology
Published in
6 min readNov 30, 2023

Merhaba, farklı ortamlarda farklı otomasyonlar koşmak istediğimizde bunların yönetimi zorlaşabiliyor. Özellikle elementlerde değişen farklılıklar bizi bu konuda zorlayabiliyorlar. Bununla birlikte farklı ortamlarda farklı fonksiyon gereksinimleri de tek bir proje içerisinde çalıştırmayı zorlaştıran sebepler arasında. Bu sebeple farklı işletim sistemleri için çalıştıracağımız test otomasyonlarını farklı repolarda tutarsak repoları kontrol etmemiz daha kolay ve daha düzenli olur. Daha önceki yazımda mobil test otomasyon projesi nasıl oluşturulur, proje için neler gereklidir ve kurulumları nasıl yapılır bunu anlatmıştım. Bu yazıyı bu linki takip ederek okuyabilirsiniz.

Şimdi bu yazıda anlatmak istediğim konu iOS ve Android cihazların otomasyonları farklı repolarda nasıl koşulur ve repolar nasıl ayrılır bunu anlatmak olacak.

Repoları Ayırmak ve Yönetmek

Normalde otomasyon projelerimiz tek bir repodan oluşuyor tek repodan oluşan bu projelerimizde classlarımızı istediğimiz gibi kullanıp yönetebiliyoruz. Fakat hem iOS hem de Android test caselerimizi, objelerimizi, elementlerimizi yönetmemiz çok kolay olmuyor. Bunların yönetimini daha kolay bir duruma getirmek için repoları ayırmayı tercih ediyoruz. Fakat elimizde 2 repo olmayacak 3 repo olacak. 3. repo nereden çıktı diye kendi kendinize sorarken cevaplayayım, bizim kullandığımız Base Test, Base Page ve utils dosyalarımızı Android ve iOS projeler için ortak kullanacağız. Bu taraflarda yapılacak değişiklikleri her iki proje için ayrı ayrı yapmak hem iş yükü açısından hem de karışıklık açısından işimizi kolaylaştırmayacak. Bu sebeple 3. bir main-framework yapımız olacak. Bu yapı içerisinde yukarıda bahsettiğim ortak kullanılan classlar ve kullanılabilecek classlar yazılacak. Yani özetlemek gerekirse Android için bir repo, iOS için bir repo ve main-framework için ayrı bir repo olmak üzere 3 repomuz olacak.

Repolar Nasıl Ayrılır?

Şimdi öncelikle ortak kullanacağımız classlar ve dosyaları belirleyip bunları src/main içerisinde eklememiz gerekiyor. Bu yapı basitçe şu şekilde olmalı;

Main Framework basit yapısı

Burada şunu sorduğunuzu duyar gibiyim, bunları src/test klasörü altında kullanıyorduk neden main klasörüne taşıdık. Şimdi Android ve iOS repolarımızda bu classlar olmayacağı için bunlara erişimlerini sağlamamız gerekiyor. Bunun yöntemi de bu main-framework için bir artifact oluşturup bu artifactı Android ve iOS projelerinde pom içerisinde dependency olarak kullanmamız gerekiyor. Bu sayede Android ve iOS projelerimiz bu classlara ulaşabiliyorlar. Burada main taşımamızın sebebi de bu artifactın oluşturulması test klasörü altında yapılamıyor main içerisinde yapılabiliyor. Bir diğer dikkat etmemiz konu TestNG problemi. TestNG dependency eklenirken scope genellikle test olarak belirtiliyor. Bu test klasörünün derlenmesini sağlayan bir yöntem. Ve TestNG bu şekilde kullanılırsa main klasörüne erişemiyor. Bunun için yapmamız gereken şey scope için compile olarak değişiklik yapmak veya scope ibaresini tamamen silmektir. Sildiğimiz zaman TestNG default olarak compile scope kullanır. Bu kısmı da halletiğimize göre main framework yapımızda pom.xml dosyamızın kodları nasıl olmalı birlikte bakalım.

<?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>org.turknet.mobile</groupId>
<artifactId>turknetMobileFramework</artifactId>
<version>${mobile-framework.version}</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mobile-framework.version>1.0</mobile-framework.version>
</properties>


<dependencies>

<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.6.0</version>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.7.1</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>

<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.1.0</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>2.18.1</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>11</source> <!--For JAVA 8 use 1.8-->
<target>11</target> <!--For JAVA 8 use 1.8-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/1.9.6/aspectjweaver-1.9.6.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>tn-maven</id>
<url>https://artifact.turknet.net.tr/repository/tn-maven/</url>
</repository>
</distributionManagement>
<repositories>
<repository>
<id>turknet-test</id>
<url>https://artifact.turknet.net.tr/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

Peki nasıl oluşturulacak bu artifact. Artifact oluşturmak için 2 yöntem var. Benim önerdiğim basit yöntem maven ile oluşturulması. Bir diğer yöntem de Intellij IDE ile oluşturulması. Maven ile oluşturulma kısmında yapacağımız sadece iki işlem var. mvn clean ve mvn install komutlarıyla artifactımızı direkt olarak target klasörünün içine oluşturabiliyoruz. Gerçekten çok basit bir yöntem. Bu oluşturduğumuz artifactın sistem pathini daha sonrasında Android ve iOS projelerimizin pom.xml dosyalarında dependency olarak ekliyoruz ve bu projelerimizde main-framework classlarımızı ve fonksiyonlarımızı kullanabiliyoruz. Bu local çalıştırılacak sistemlerde kullanılması optimal olan bir yöntem. Peki takım arkadaşlarımızla çalışacağımız zaman bu yöntem ne kadar sağlıklı olabilir? Ben main-framework içerisinde her değişiklik yaptığımda oluşturuduğum artifactı takım arkadaşıma mı göndermem gerekecek? Bu çok zor bir işlem ve gereksiz bir işlem. Bunun yerine DevOps arkadaşlardan destek alarak Nexus içerisinde otomatik olarak artifact oluşturacak bir pipeline sistemi oluşturduk. Main-framework içerisinde bir değişiklik yapıldığı zaman otomatik olarak Nexus yeni bir artifact oluşturup bunun linkini bize veriyor. Bu sayede sadece bu linki Android ve iOS projelerimizin pom.xml dosyalarında dependency olarak eklediğimizde main-frameworke erişebiliyoruz. Ve takımdaki herkes bağımsız bir şekilde otomasyon üstünde çalışmalarına devam edebiliyorlar. Tek yapmaları gereken artifactın oluşturulan versiyonunu değiştirmeleri. Hemen bakalım bu dependency yapısı nasıl oluyormuş;

<?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>org.example</groupId>
<artifactId>turknetMobile</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>


<dependencies>

<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.6.0</version>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.6.0</version>
<!-- <scope>test</scope>-->
</dependency>

<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>

<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.1.0</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>2.18.1</version>
</dependency>


<!-- <dependency>
<groupId>org.turknet.mobile</groupId>
<artifactId>turknetMobileFramework</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>/Users/bakican.boydas/Documents/projects/mobile-automation-android/target/turknetMobileFramework-1.0.jar</systemPath>
</dependency>-->

<dependency>
<groupId>org.turknet.mobile</groupId>
<artifactId>turknetMobileFramework</artifactId>
<version>1.0.main.48</version>
</dependency>


</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>11</source> <!--For JAVA 8 use 1.8-->
<target>11</target> <!--For JAVA 8 use 1.8-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testngSuites/testng.xml</suiteXmlFile>
</suiteXmlFiles>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/1.9.6/aspectjweaver-1.9.6.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

<distributionManagement>
<repository>
<id>turknet-test</id>
<url>https://artifact.turknet.net.tr/repository/tn-maven/</url>
</repository>

</distributionManagement>
<repositories>
<repository>
<id>turknet-test</id>
<url>https://artifact.turknet.net.tr/repository/tn-maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

</project>

Yukarıdaki kodda da göreğiniz üzere yorum satırları içerisinde bir bölüm mevcut. Bu bölüm local olarak çalışırken kullandığım ve oluşturulan artifact ile jar dosyasının pathini dependency olarak verdiğim bir bölüm. Bu bölüme remote olarak çalışırken ihtiyacım yok çünkü Nexus ile birlikte kullandığım dependency bu kod parçası;

<dependency>
<groupId>org.turknet.mobile</groupId>
<artifactId>turknetMobileFramework</artifactId>
<version>1.0.main.48</version>
</dependency>

Ve bununla birlikte bu kısmı da kullanmamız gerekiyor bu kısımda dependency olarak kullanılacak versiyonu nereden çekeceğimizi belirtiyoruz;


<distributionManagement>
<repository>
<id>turknet-test</id>
<url>https://artifact.turknet.net.tr/repository/tn-maven/</url>
</repository>

</distributionManagement>
<repositories>
<repository>
<id>turknet-test</id>
<url>https://artifact.turknet.net.tr/repository/tn-maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

Sonuç olarak farklı repolar ile nasıl bağlantı sağlandığını görmüş olduk.

Android ve iOS Proje Yapısı

Burada 2 proje için genel yapı tamamen aynı. Class isimlendirmeleri ve yazılan test caseler tamamen aynı. Burada tek değişen şey testng.xml dosyalarında parametre olarak gönderdiğimiz değerler ve pageObjectlerin içerisinde yazılan elementler. Genel yapımızın nasıl olacağını resimde görebilirsiniz;

Android ve iOS genel yapısı

Burada constant yapısını kullanmamızın sebebi artık BaseTest ve properties dosyalarını repoları ayırdığımız için birlikte kullanamamız. Normalde properties dosyalarımızı BaseTest içerisinde tanımladıktan sonra test classlarımız içerisinde gerekli yerlerde kullanıyorduk. Şimdi 2 proje için de constants yapısını kullanarak bu bağımlılıktan kurtulmuş olduk. Bununla birlikte Android için elementleri locate ederken id ve xpath kullanabilirken iOS için yalnızca xpath kullanabiliyoruz. Bu biraz iOS’un kendi yapısından kaynaklanan bir durum. Bunlar haricinde yapımız tamamen aynı. Kullandığımız ortak fonksiyonları yine BasePage tarafından kullanıyoruz farklılık gördüğümüz noktalarda ise farklılıkları pageObjectler içerisinde değiştiriyoruz. Örnek vermek gerekirse Android deviceBack yani cihazın geri tuşu fonksiyonunu kullanabilirken iOS’ta böyle bir durum mevcut değil iOS tarafında uygulama içerisindeki geri tuşunu kullanıyoruz. Bu tarz ufak farklılıklar testi yazarken karşınıza çıkacaktır. Öncesinde bunlar için yapmanız gereken bir işlem yok.

Kapanış

Bu yazıda amacımız var olan otomasyon projemiz için farklı repolara ayırıp nasıl kullanabiliriz bunu anlatmaktı. Bu yazıyı ve projeyi birlikte hazırladığımız Ayşenur Çelik arkadaşıma da teşekkür ederek yazıyı tamamlıyorum. Okuduğunuz için teşekkür ederiz.

İlk projenin linki

https://medium.com/@bakicanboydas/java-testng-appium-and-more-e343365e5bc2

--

--