Jetpack Compose’da ViewModel için Unit Testler Nasıl Yazılır?
Giriş 🌟
Bu makalede Jetpack Compose’da ViewModel’i test etmek için unit testlerin nasıl uygulanacağını öğreneceğiz. Ön koşul olarak ViewModel’i Jetpack Compose’da nasıl uygulayacağınızı bilmeniz gerekir.
Android Uygulama Geliştirmede Unit Testlerin Önemi
Android uygulama geliştirirken unit testler yazmak oldukça önemlidir. Peki neden?
- Unit testler, hataları erkenden tespit ederek kod kalitesini garanti eder, uzun vadede zamandan ve kaynaklardan tasarruf sağlar.
- Unit testler, kod tabanı geliştikçe yeni değişikliklerin mevcut işlevselliği bozmamasını sağlayarak kod bakımını kolaylaştırır.
- Unit testler, geliştiricileri kodun organizasyonu ve yapısı hakkında düşünmeye zorlayarak kod tasarımını geliştirir.
Genel olarak unit testler, yüksek kaliteli, bakımı yapılabilir ve ölçeklenebilir Android uygulamaları geliştirmek için gereklidir.
True False Uygulamasını Test Etme
True False uygulaması, ViewModel bileşenini test etmek için unit testler yazmayı içeren, Jetpack Compose ile oluşturulmuş basit bir doğru-yanlış oyunudur.
Uygulamadaki genel akış şu şekildedir:
💠 Kullanıcıya doğru-yanlış sorusu sorulur.
💠 Kullanıcı cevabı doğru veya yanlış olarak işaretler.
💠 Kullanıcının yanıtı güncellenir.
💠 Kullanıcı doğru cevap verirse puanı artar.
💠 Kullanıcı yanlış cevap verirse puanı değişmez.
💠 Kullanıcı tüm soruları yanıtladığında oyun sona erer.
💠 Kullanıcı oyundan çıkabilir veya tekrar oynayabilir.
True False uygulamasını test etmeye başlamak için projenin başlangıç koduna buradan erişebilirsiniz. Hadi başlayalım!
Bağımlılıkları Ekleme
build.gradle.kts dosyasını açın ve dosyanın bağımlılıklar bölümüne aşağıdaki bağımlılığı ekleyin:
ViewModel Sınıfını İnceleme
GameViewModel sınıfı için unit testler yazmadan önce sınıfı inceleyelim.
🚩 init{}: Başlatma bloğu oyunu başlatmak için kullanılır, l fonksiyonunu çağırır.
🚩 resetGame(): Bu fonksiyon, oyunu sıfırlayarak ve kullanıcıya yanıtlaması için yeni bir soru sağlayarak oyunun başlangıç durumunu ayarlar.
Daha önce sorulmuş olan soruları takip etmek için kullanılan usedQuestions listesini temizler. Daha sonra yeni bir soruyu almak için getQuestion() fonksiyonunu çağırır ve _uiState değerini yeni soru ve doğru cevabıyla günceller.
🚩 getQuestion(): Bu fonksiyon bir Question nesnesi döndürür.
random() fonksiyonunu kullanarak mevcut tüm soruların listesinden rastgele bir soru seçer. Daha sonra, usedQuestions adı verilen bir listede olup olmadığını kontrol ederek, seçilen sorunun daha önce kullanılıp kullanılmadığını kontrol eder. Soru zaten kullanılmışsa, fonksiyon başka bir rastgele soru seçmek için yinelemeli olarak kendisini çağırır. Seçilen soru daha önce kullanılmamışsa, usedQuestions listesine eklenir ve geçerli soru olarak döndürülür.
🚩 updateUserAnswer(): Bu fonksiyon, userAnswer değişkeninin değerini kullanıcının girdiği seçimle güncellemek için çağrılır.
🚩 checkUserAnswer(): Bu fonksiyon, kullanıcının yanıtlarını kontrol eder ve verilen yanıt doğru ise skorun güncellenmesini sağlar.
userAnswer’ın uiState.value.correctAnswer ile eşleşip eşleşmediğini kontrol eder. Eşleşirlerse kullanıcının puanı, _uiSate.value.score’a SCORE_INCREASE değeri eklenerek güncellenir. Ardından, _uiSate.update() işlevini kullanarak isAnswerWrong’u false olarak ayarlayarak kullanıcı arayüzü durumunu günceller. Son olarak oyun puanını yeni değerle güncellemek için updateGameScore() adı verilen başka bir fonksiyonu çağırır. Kullanıcının yanıtı doğru yanıtla eşleşmiyorsa isAnswerWrong değerini true olarak ayarlayarak kullanıcı arayüzü durumunu günceller.
🚩 updateGameScore(): Bu fonksiyon kullanıcının oyun skorunu günceller.
Oyunun bitip bitmediğini belirlemek için usedQuestions listesinin boyutunun MAX_NO_OF_QUESTIONS’a eşit olup olmadığını kontrol eder. Tüm sorular kullanılmışsa _uiState, güncelleme işlevi kullanılarak güncellenir. isGameOver true olarak ayarlanır ve puan, updatedScore değeriyle güncellenir. Eğer hala sorular varsa, _uiState isGameOver değiştirilmeden updatedScore ile yalnızca puan güncellenecek şekilde güncellenir.
🚩 goToNextQuestion(): Bu fonksiyon, kullanıcı arayüzü durumunu yeni soru ve yanıtla güncelleyerek oyunu bir sonraki soruya taşır.
Kullanılan soru sayısının maksimum soru sayısına eşit olup olmadığını kontrol eder. Eğer öyleyse, bu oyunun bittiği ve kullanıcı arayüzü durumunda isGameOver değerinin true olarak güncellendiği anlamına gelir. Eğer oyun bitmediyse, bir sonraki soru ve cevaba ulaşmak için getQuestion() fonksiyonunu çağırır. Daha sonra soruya currentQuestion’ı, cevaba trueAnswer’ı ve currentQuestionCount’u geçerli soru sayısı artı bire ayarlayarak kullanıcı arayüzü durumunu günceller.
GameViewModel sınıfındaki fonksiyonları ve ne işe yaradıklarını detaylı bir şekilde inceledik.
Unit Testler Yazma
Etkili Unit Testlerin Temel Özellikleri
İyi bir unit testin dört temel özelliği olması gerekir:
💠 Sınıf veya fonksiyon gibi belirli bir kod birimini test etmeye odaklanılmalıdır. Bu, testin kapsamının dar olmasını sağlar ve böylece tek tek kod parçalarının doğruluğunu kontrol eder.
💠Kolayca anlaşılabilir olmalı, testin arkasındaki amaç kodu okuyan herhangi bir geliştirici için hemen anlaşılmalıdır.
💠Kod değişikliği yapılmadan kaç kez çalıştırılırsa çalıştırılsın sürekli geçmeli veya başarısız olmalıdır.
💠 Kendi kendine yetebilmelidir, herhangi bir insan etkileşimi veya kurulum gerektirmeden izole bir şekilde çalışmalıdır.
Şimdi bu temel özellikleri dikkate alarak unit testleri yazmaya başlayalım.
1. Adım
GameViewModel sınıfa ünit testler yazmak için GameViewModelTest adında bir sınıf oluşturun ve GameViewModelTest sınıfının içinde bir gameViewModel özelliği oluşturun ve buna GameViewModel sınıfının bir örneğini atayın.
2. Adım
gameViewModel_Initialization_FirstQuestionLoaded() adında bir fonksiyon oluşturun ve buna @Test anotasyonunu ekleyin.
Bu test, gameViewModel başlatıldığında, ilk gameUiState’in boş olmayan bir currentQuestion ve correctAnswer değerine sahip olduğunu, currentQuestionCount değerinin 1'e, score değerinin 0'a, isAnswerWrong degerinin null’a ve isGameOver’ın false’a eşit olduğunu kontrol eder.
🚩 GameUiState sınıfının ilk örneğini almak için viewModel.uiState.value özelliğine erişin ve bunu yeni bir gameUiState salt okunur değişkenine atayın.
🚩 currentQuestion.isEmpty() değerinin ve correctAnswer.isEmpty() değerinin ve isAnswerWrong() değerinin false olarak ayarlandığını doğrulamak için assertFalse() fonksiyonlarını ekleyin.
🚩 currentQuestionCount değerinin 1'e, score değerinin 0'a, isAnswerWrong() değerinin null’a ayarlandığını doğrulamak için assertTrue() fonksiyonlarını ekleyin.
3. Adım
gameViewModel_AnsweredCorrectly_ScoreUpdated() adında bir fonksiyon oluşturun ve buna @Test anotasyonunu ekleyin.
Bu test, kullanıcı bir soruyu doğru yanıtladığında GameViewModel sınıfının skoru doğru şekilde güncellemesini kontrol eder.
🚩 GameViewModel’in mevcut kullanıcı arayüzü durumunu alın.
🚩 Kullanıcının soruyu doğru yanıtlamasını simüle etmek için updateUserAnswer() fonksiyonunu doğru yanıtla çağırın.
🚩 Kullanıcının cevabının doğru olup olmadığını kontrol etmek için checkUserAnswer() fonksiyonunu çağırın.
🚩 State’in doğru bir şekilde çalıştığını ve gameUiState.isAnswerWrong değerinin false değerine eşit olduğunu ve gameUiState.score değerinin SCORE_INCREASE değerine eşit olup olmadığını kontrol etmek için assertEquals() fonksiyonlarını ekleyin.
4. Adım
gameViewModel_AnsweredIncorrectly_ScoreNotUpdated() adında bir fonksiyon oluşturun ve buna @Test anotasyonunu ekleyin.
Bu test, kullanıcı bir soruyu yanlış yanıtladığında GameViewModel sınıfının skoru güncellememesini kontrol eder.
🚩 incorrectAnswer adında bir değişken tanımlayın ve ona “and” değerini atayın .
🚩 Kullanıcının soruyu yanlış yanıtlamasını simüle etmek için yanlış yanıtla updateUserAnswer() fonksiyonunu çağırın .
🚩 Kullanıcının cevabının doğru olup olmadığını kontrol etmek için checkUserAnswer() fonksiyonunu çağırın.
🚩 Bir gameUiState değişkeni oluşturun ve ona gameViewModel.uiState.value değerini atayın.
🚩 gameUiState.isAnswerWrong özelliğinin değerinin true değerine, gameUiState.score değerinin ise 0'a eşit olup olmadığını kontrol etmek için assertEquals() fonksiyonlarını ekleyin.
5. Adım
gameViewModel_AllQuestionSolved_UiStateUpdatedCorrectly() adında bir fonksiyon oluşturun ve buna @Test anotasyonunu ekleyin.
Bu test, oyundaki tüm sorular çözüldüğünde gameViewModel’in UI state’inin doğru şekilde güncellenip güncellenmediğini kontrol eder.
🚩 expectedScore adında bir değişken tanımlayın ve ona 0 değerini atayın .
🚩 Bir gameUiState değişkeni oluşturun ve ona gameViewModel.uiState.value değerini atayın.
🚩 Oyundaki her soruyu çözmeyi simüle etmek için MAX_NO_OF_QUESTIONS kez yinelenen bir repeat döngüsü yazın.
🚩 Döngünün içinde, her yineleme için expectedScore’u SCORE_INCREASE kadar artırın .
🚩 Kullanıcının soruyu doğru yanıtladığını simüle etmek için updateUserAnswer() fonksiyonunu doğru yanıtla çağırın.
🚩 Kullanıcının cevabının doğru olup olmadığını kontrol etmek için checkUserAnswer() fonksiyonunu çağırın.
🚩 Bir sonraki soruya geçmek için goToNextQuestion() fonksiyonunu çağırın.
🚩 gameUiState değerini yeni gameViewModel.uiState.value değeriyle güncelleyin.
🚩 expectedScore’un gameUiState’in score değeriyle eşleştiğinden emin olmak için assertEquals() fonksiyonunu ekleyin.
🚩 Döngüden sonra, MAX_NO_OF_QUESTIONS’ın gameUiState’in currentQuestionCount değeriyle eşleştiğinden emin olmak için assertEquals() fonksiyonunu ekleyin. Bu, tüm soruların çözüldüğü anlamına gelir.
🚩 gameUiState’in isGameOver değerinin doğru olduğundan emin olmak için assertTrue() fonksiyonunu ekleyin. Bu, tüm sorular çözüldükten sonra oyunun bittiği anlamına gelir.
Testleri Çalıştırma
GameViewModel sınıfı için yazacağımız tüm unit testlerini tamamladık.
GameViewModelTest sınıfındaki tüm testleri çalıştırmak ve sonuçları görmek için Run test ikonuna tıklayın.
Aşağıda test sonuçlarını görebilirsiniz.
Yazdığımız tüm unit testler geçti!
Sonuç
Unit testler yazmanın yazılım geliştirme için çeşitli avantajları vardır. Hataların erken tespit edilmesine yardımcı olur, kod kalitesini artırır, daha hızlı geri bildirim sağlar, geliştiricinin güvenini artırır, yeniden düzenlemeyi kolaylaştırır ve çevik geliştirmeyi destekler. Bu artılardan yararlanmak için Android uygulamaları geliştirirken birim testleri yazmayı unutmayın.
Okuduğunuz için teşekkürler.
Kodun tamamı için: