Merhaba arkadaşlar,
mobilhanem.com üzerinden anlattığımız/yayınladığımız derslere bugün sizlere Android Espresso UI Test kullanımını anlatacağım.
Bir uygulama üzerinden temel seviyede espresso testi nasıl yapılır, hangi aşamalardan oluşur sizlere göstermeye çalışacağım. Biz android geliştiricilerin yazdığı kodlar kadar test koşullarınıda oluşturması gerçekten önemlidir. Unit Test, UI Test gibi test yapılarının neler olduğunu bilmemizde fayda var. Yazılım dünyası kadar test dünyasıda gerçekten kapsamlı ve ayrıntılı bir yapıya sahiptir. Ben de yeni yeni bu alanda araştırmalar yapmaya başladığım için sizlere öğrendiğim kadar bilgileri aktaracağım.
Android Espresso UI Test
Android Espresso UI Test, Android de kullanıcı arayüz testlerini oluşturup daha sonra o test koşullarını koştuğumuz bir araçtır. Espresso testleri Android 2.3.3 (API seviyesi 10) ve üstünü çalıştıran cihazlarda çalışabilir.
Espresso testlerimizi senaryolar üzerine oluşturacağız ve bu senaryolarıda yaratmak için Gherkin dilini kullanacağız. Peki nedir bu Gherkin ? Gherkin bir çeşit DSL (Domain Specific Language) olup, konuşma dilinin direk yazıya aktarılmış şeklidir. Çeşitli dil desteği mevcut olup; Cucumber yapısının bu söz dizimini anlamasına yardımcı olur. Desteklenen dil seçeneklerini görmek için bu linki inceleyebilirsiniz.
Cucumber kütüphanesi düz metin olarak tanımlanmış kullanım senaryolarını otomatize edilmiş test koşullarına dönüştürmeye yardımcı olur. Cucumber kullanmak proje süreçlerinde yer alan diğer kişilerinde bu dili anlamasını kolaylaştırır.
Şimdi yapmamız gereken Android Studio da Gherkin plugini projemize entegre etmek olacaktır.
Android Studio -> Preferences -> Plugins kısmına Gherkin aratıyoruz ve plugini yüklüyoruz.
Daha sonra app modülündeki build.gradle kısmına aşağıdaki kod parçalarını ekliyoruz. Böylece cucumber kütüphanesini projemizde kullanabileceğiz.
build.gradle
androidTestImplementation 'info.cukes:cucumber-android:1.2.5' androidTestImplementation 'info.cukes:cucumber-picocontainer:1.2.4'
Yine build.gradle dosyasına aşağıdaki source set kodunu ekliyoruz.
build.gradle
sourceSets { androidTest { assets.srcDirs = ['src/androidTest/assets'] } }
Şimdi Instrumentation sınıfını oluşturuyoruz.
Instrumentation.java
package com.mobilhanem.alper.espressotestexample.test; import android.os.Bundle; import android.support.test.runner.MonitoringInstrumentation; import cucumber.api.android.CucumberInstrumentationCore; public class Instrumentation extends MonitoringInstrumentation { private final CucumberInstrumentationCore instrumentationCore = new CucumberInstrumentationCore(this); @Override public void onCreate(Bundle arguments) { super.onCreate(arguments); instrumentationCore.create(arguments); start(); } @Override public void onStart() { super.onStart(); waitForIdleSync(); instrumentationCore.start(); } }
Son olarak build.gradle yapısı aşağıdaki gibi olmalıdır. testApplicationId ve testInstrumentationRunner önemli kod parçacıklarıdır eğer düzgün bir şekilde paket adlarını belirtmezsek espresso testlerini koşmaya çalıştığımızda hatalarla karşılaşacağız.
build.gradle
apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "com.mobilhanem.alper.espressotestexample" minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName "1.0" testApplicationId "com.mobilhanem.alper.espressotestexample.test" testInstrumentationRunner "com.mobilhanem.alper.espressotestexample.test.Instrumentation" } sourceSets { androidTest { assets.srcDirs = ['src/androidTest/assets'] } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:design:28.0.0' implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:rules:1.0.2' androidTestImplementation 'info.cukes:cucumber-android:1.2.5' androidTestImplementation 'info.cukes:cucumber-picocontainer:1.2.4' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' }
Cucumber için test senaryolarını oluşturmamız gerekiyor bu test senaryolarının da oluşturulması için feature tanımlamaları yapmalıyız. Oluşturacağımız bu feature ların içine Gherkin dilini de kullanarak test aşamalarını oluşturacağız.
Öncelikle yapmamız gereken adımlar :
- androidTest klasörümüz için New -> Edit File Templates… adımlarını izliyoruz.
- Açılan ekranda + butonuna tıklıyoruz ve aşağıdaki gibi Name kısmına Cucumber feature file , Extension kısmına da feature yazıyoruz.
- Android Studio daki projemizin src -> androidTest klasörü altına assets oluşturuyoruz.
- Android Studio daki projemizin src -> androidTest -> assets klasörü altına feature dosyasını oluşturuyoruz.
- Daha sonra src -> androidTest -> assets -> feature klasörü altına da aşağıda gördüğüz gibi cucumber feature file oluşturuyoruz. ( hangi feature özelliğini koşmak istiyorsak onu tanımlıyoruz biz login kısmını test edeceğimiz için login adını verdik )
Şimdi oluşturduğumuz bu login özelliğinin içini dolduralım. Aşağıdaki yapıda gördüğünüz gibi login özelliklerini Given, When, And, Then gibi Gherkin dili koşullarını kullanarak tanımladık.
login.feature
Feature: Login User Scenario Outline: Login User Scenario Given create login activity When input user name <username> And input user password <password> And press login button Then open main activity Examples: | username | password | | alper9191 | 919091 | | alper9191 | 919092 |
Espresso Test Step
Yukarıda belirttiğimiz özelliğe karşılık gelen step sınıfını oluşturuyoruz. Belirtilen feature komutlarının stepler tarafından anlaşılabilmesi için bire bir aynı cümlelerin aşağıdaki step de yer alması gerektiğini göreceksiniz.
LoginActivitySteps.java
package com.mobilhanem.alper.espressotestexample.test; import android.app.Activity; import android.support.test.espresso.action.ViewActions; import android.support.test.rule.ActivityTestRule; import com.mobilhanem.alper.espressotestexample.activities.LoginActivity; import com.mobilhanem.alper.espressotestexample.R; import org.junit.Rule; import cucumber.api.CucumberOptions; import cucumber.api.java.After; import cucumber.api.java.Before; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.Espresso.pressBack; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.typeText; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static junit.framework.Assert.assertNotNull; @CucumberOptions(features = "features") public class LoginActivitySteps { @Rule public ActivityTestRule<LoginActivity> activityLoginTestRule = new ActivityTestRule<>(LoginActivity.class); private Activity activity; @Before public void setup() { activityLoginTestRule.launchActivity(null); activity = activityLoginTestRule.getActivity(); } @After public void tearDown() { activityLoginTestRule.getActivity().finish(); } @Given("^create login activity") public void create_login_activity(){ if (activity == null) { setup(); } assertNotNull(activity); } @When("^input user name (\\S+)$") public void input_user_name(final String username) { onView(withId(R.id.userNameEdit)).perform(typeText(username)); ViewActions.closeSoftKeyboard(); } @When("^input user password (\\S+)$") public void input_user_password(final String password) { onView(withId(R.id.passwordEdit)).perform(typeText(password)); } @When("^press login button$") public void press_login_button() { onView(withId(R.id.loginButton)).perform(click()); } @Then("^open main activity$") public void open_main_activity() { onView(withId(R.id.mainTextView)).check(matches(isDisplayed())); pressBack(); } }
androidTest klasörü altında yer alan yapı aynı aşağıdaki gibi olmalıdır. featureları oluşturduğumuz feature klasörü altında konumlandırmayı ve feature lara karşılık gelen steps leride yine oluşturduğumuz test klasörü altına konumlandırmayı unutmayalım.
Bütün gereksinimleri tamamladığımıza göre şimdi testleri nasıl çalıştacağımızı inceleyelim.
Espresso Testlerini Terminalden Koşma
./gradlew connectedCheck
Espresso Testlerini Android Studio Üzerinden Koşma
Android Studio da run kısmında yer alan Edit Configurations… seçeneğine tıklıyoruz ve karşımıza gelen ekranda aşağıda görüldüğü gibi + basarak Android Instrumented Tests tabını açıyoruz.
Açılan sayfada Name kısmına UI Test yazdık ve module olarak da app seçiyoruz. Bu aşamlarıda tamamladıktan sonra Android Studio da UI Test i direk run edebiliyoruz run ettiğimizde ise projede yer alan Espresso testlerini koşmaya başladığını göreceksiniz.
Kaynak koda göre test koşulunu çalıştırdığımızda Login sayfasında kullanıcı adı ve şifreyi doğru olarak verdiğimiz için test aşamasının başarılı bir şekilde geçtiğini göreceksiniz. Aşağıdaki çıktıda gördüğünüz gibi kaç test çalıştırılmış kaç test başarılı bir şekilde geçmiş görebilirsiniz.
Kaynak kodu indirip çalıştırabilirsiniz test case lerini ya da aşama aşama anlatılanları kendi projenizde uygulamayabilirsiniz. Burada önemli olan Espresso nun cucumber ile birlikte nasıl kullanıldığı ve neden kullanmamız gerektiğini iyi kavramak olacaktır.
Evet arkadaşlar Android Espresso UI Test aşamalarını Cucumber ile birlikte sizlere anlatmaya çalıştım. Espresso ile test yazmak çok daha derin bir konu olduğu için temel başlıkları anlattım. Ben de bu konuda daha çok ilerlemeye başladıkça bu derste güncellemeler ve eklemeler yapacağım.
Tüm Android Ders, Proje ve Kaynak Kodlar için tıklayınız.
Mobilhanem.com üzerinden anlattığımız android uygulama geliştirme derslerine devam edeceğiz. Konu hakkında sorunuzu yorum alanından sorabilirsiniz. Konu dışı sorularınızı ve tüm yazılımsal sorularınızı sorucevap.mobilhanem.com sitemizden de sorabilirsiniz.
Bir dahaki dersimizde görüşmek dileğiyle..
10