Espresso İle Arayüz Testleri

Espresso, uygulama üzerinde ki testlerimizi simüle edebilen ve bizi her değişiklikte aynı testleri yapmaktan kurtaran, Google tarafından geliştirilmiş bir framework’tür. Çoğu zaman uygulamayı cihaz üzerinde çalıştırırız. Bir login ekranı test ederiz. Kullanıcı adını yanlış yazarız test ederiz. Parolayı yanlış yazarız test ederiz. Kullanıcı adını girip parolayı boş bırakarak test ederiz. Kayıtlı olmayan bir kullanıcı adını deneriz vs vs vs. Bu sadece login ekranı içindi, uygulama üzerinde daha birçok test senaryoları deneriz. Bu çok uzun zaman alan bir işlemdi ve Espresso(ve diğer UI test framework’leri) bu sorunu ortadan kaldırmak için geliştirildi.

Espresso ile teste başlamak için önce build.gradle dosyasına Espresso’nun referansını tanımlamamız gerekiyor. Genelde bu tanımlanmış olarak geliyor.

 

dependencies {
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
}

İlk olarak bir login ekranı tasarlamakla işe başlayalım.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.ugurc.espressoexample.MainActivity">

    <EditText
        android:id="@+id/edtUserName"
        android:layout_width="140dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="80dp"
        android:hint="Kullanıcı Adı"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="104dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="104dp" />

    <EditText
        android:id="@+id/edtPassword"
        android:layout_width="140dp"
        android:layout_height="wrap_content"
        tools:layout_constraintTop_creator="1"
        android:hint="Şifre"
        android:layout_marginTop="48dp"
        app:layout_constraintTop_toBottomOf="@+id/edtUserName"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginStart="104dp"
        android:layout_marginLeft="104dp" />

    <Button
        android:id="@+id/btnLogin"
        android:text="Giriş"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="72dp"
        app:layout_constraintTop_toBottomOf="@+id/edtPassword"
        android:layout_marginEnd="120dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginRight="120dp" />
</android.support.constraint.ConstraintLayout>
activity_main.xml

 

package com.example.ugurc.espressoexample;

import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

    private EditText edtUserName, edtPassword;
    private Button btnLogin;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        edtUserName = (EditText) findViewById(R.id.edtUserName);
        edtPassword = (EditText) findViewById(R.id.edtPassword);
        btnLogin    = (Button)   findViewById(R.id.btnLogin);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                doLogin(v);
            }
        });
    }

    private void doLogin(View v) {
        String userName = edtUserName.getText().toString();
        String password = edtPassword.getText().toString();

        if (userName.equals("ugurcmk") && password.equals("1234"))
            Snackbar.make(v,"Giriş Yapıldı.",Snackbar.LENGTH_LONG).show();
        else
            Snackbar.make(v,"Kullanıcı Bilgileriniz Hatalı!",Snackbar.LENGTH_LONG).show();
    }
}
MainActivity.java

 

Login ekranımız bitti. Şimdi test sınıfını yazmaya başlayabiliriz. Fakat ilk önce Espresso ile ilgili bilgimizi genişletelim.  Espresso 3 parçalı bir yapıdan oluşur.

onView(withId(R.id.my_view)
       .check(matches(isDisplayed()))
           .perform(click());
           

onView() methodu ile hangi UI elemanını test edeceğimizi belirliyoruz. Burada iki fonksiyon var withId() ve withText() methodları. withId() methodu findViewById() methoduyla aynı şekilde çalışıyor aslında, farklı olan ise withText() methodu. Bu method kendisine verilen string değeri ile view’u buluyor. Örneğin bir butonun üzerinde ki text ile butonu bulabiliyoruz. İkinci satırda check() methodu ile view’dan beklediğimiz davranışı sağlıyor mu sağlamıyor mu onu test ediyoruz. Örneğin yukarıda ki satırda view “ekranda gözüküyor olmalı” davranışını test ediyoruz. check() methodu içerisinde üç method çalıştırabiliriz. Birincisi yukarıda görüldüğü gibi matches() fonksiyonu. Bu method ile view’un yaratıldığını kontrol ediyor ve  içine yazılan fonksiyon ile view’un durumunu kontrol ediyoruz. Yukarıda ki kod bloğundan örnek vericek olursak my_view view’unun yaratılmış olması ve ekranda gözüküyor olması gerekir yoksa fonksiyon hata döner. doesNotExist() methodu ile view’un yaratılmadığını kontrol ediyoruz. selectedDescendantsMatch() methodu ile view’un belirtilen bir sınıftan türeyip türemediğini kontrol ediyor ve ikinci paremetresinde matcher objesi ile kendisinden beklenilen davranışı yerine getirip getirmediği kontrol ediliyor. Geldik üçüncü yapımız olan perfom() methodu. Bu method içinde ki tanımlı 4 fonksiyona göz atacağız. En çok kullanılacak olan dört method diğerlerini android’in dökümantasyonunda bulabilirsiniz. İlki click() fonksiyonu. Belirttiğimiz view’a tıklama işini yapıyor. typeText() fonksiyonu verdiğimiz text’i view’a yazıyor. pressKey() fonksiyonu kendisine verilen keycode ile klavye olayını gerçekleştirir. Örneğin enter tuşuna basmak gibi.

Şimdi test sınıfımıza geri dönebiliriz.

import android.content.Intent;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
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 android.support.test.espresso.matcher.ViewMatchers.withText;

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
    ActivityTestRule<MainActivity> testRule = new
            ActivityTestRule<>(MainActivity.class);

    @Test
    public void checkDisplayItems(){
        testRule.launchActivity(new Intent());
        onView(withText("Giriş")).check(matches(isDisplayed()));
        onView(withId(R.id.edtPassword)).check(matches(isDisplayed()));
        onView(withId(R.id.edtUserName)).check(matches(isDisplayed()));
    }

    @Test
    public void checkDoLogin(){
        testRule.launchActivity(new Intent());
        onView(withId(R.id.edtUserName)).perform(typeText("ugurcmk"), closeSoftKeyboard());
        onView(withId(R.id.edtPassword)).perform(typeText("1234"), closeSoftKeyboard());
        onView(withId(R.id.btnLogin)).perform(click());
        onView(withText("Giriş Yapıldı.")).check(matches(isDisplayed()));
    }

}
MainActivityTest.java

 

Burada ilk olarak test rule’umuzu belirledik sonrasında test methodlarımızı yazdık. checkDisplayItems() methodu kullanıcı adı, parola ve buton nesnelerinin ekranda görünüp görünmediğini kontrol ediyor. Sonraki method da ise, typeText() fonksiyonu ile önce forma kullanıcı adını ve parolayı yazıyoruz sonra click() methodu ile butona tıklıyoruz. Butona tıkladığımızda Snackbar üzerinde sonucu gösteriyoruz. Bunun testini de withText() methodu ile yapıyoruz. Snackbar üzerinde ki text ile withText() methoduna verdiğimiz text’ler eşitse testlerimiz başarılı bir şekilde sonlanacak diğer durumda hata verecektir. Yaptığınız testlerde yeşili yakalamanız dileğiyle  🙂