Test Store Genel Bakış
0:02:00Android icin RevenueCat Test Store kurulum kilavuzuna hos geldiniz!
Uygulama ici satin alma testleri her zaman zor olmustur. Sandbox hesaplari kurmak, test urunleri olusturmak, uygulama incelemelerini beklemek ve guvenilmez ag kosullarini yonetmek gerekiyordu. RevenueCat'in Test Store'u belirleyici, hizli ve guvenilir bir test ortami saglayarak bu sorunlari cozer.
Test Store Nedir?
Test Store, Google Play Store'a baglanmadan uygulama ici satin alma akislarini test etmenizi saglayan RevenueCat'in yerlesik test ortamidir. Tum yeni RevenueCat projelerine otomatik olarak saglanir ve satin alma sonuclari uzerinde tam kontrol sunar.
Ogrenecekleriniz
Bu codelab'de Android gelistirme icin RevenueCat'in Test Store kurulumu ve kullaniminin tum surecini ogreneceksiniz. RevenueCat panelinde Test Store'u etkinlestirmek ve Android uygulamanizi Test Store API anahtarini kullanacak sekilde yapilandirmakla baslayacaksiniz. Ardindan belirleyici sonuclarla satin alma akislarini test etmeyi, uygulama ici satin alma mantigi icin otomatik birim testleri yazmayi ve GitHub Actions kullanarak bu testleri CI/CD pipeline'iniza entegre etmeyi ogreneceksiniz.
Test Store'un Avantajlari
Test Store, uygulama ici satin alma test yontemini devrim niteliginde degistiriyor. Google Play kurulumu veya uygulama onayini beklemenizi gerektiren mevcut test yontemlerinin aksine, Test Store anlik test yetenekleri sunar. Satin alma sonuclari uzerinde tam belirleyici kontrol saglar. Islemin basarili olup olmayacagi, basarisiz olup olmayacagi veya iptal edilip edilmeyecegi tamamen size baglidir. Bu, guvenilmez ag baglantilari veya guvenilmez sandbox ortamlariyla ugrasmaniza gerek olmadigini gosterir.
Gercek guc, otomatik testler yazmayi baslattiginizda ortaya cikar. Test Store'u kullanarak GitHub Actions gibi CI/CD sistemleri dahil tum ortamlarda tutarli olarak calisan satin alma mantigi icin guvenilir birim testleri olusturabilirsiniz. Bu sayede satin alma akislarini hizla yineleyerek degisiklikleri dakikalar veya saatler yerine saniyeler icinde test edebilirsiniz.
On Kosullar
Baslamadan once asagidakileri kontrol edin:
- RevenueCat hesabi (revenuecat.com'da ucretsiz)
- RevenueCat SDK entegre edilmis Android projesi (surum 9.0.0 veya ustuu)
- Kotlin ve Android gelistirme hakkinda temel bilgi
- Jetpack Compose hakkinda anlayis (istege bagli, UI ornekleri icin)
Panelde Test Store'u Etkinlestirme
0:03:00Ilk adim, RevenueCat panelinde Test Store'u etkinlestirmek ve Test Store API anahtarini almaktir.
Panele Erisim
RevenueCat paneline giris yapin ve sol kenar cubugu menusundeki Apps & providers bolumune gidin. Burada bagli tum uygulamalarinizi ve mevcut magaza entegrasyonlarinizi bulabilirsiniz.
Test Store Olusturma
Apps & providers bolumunde mevcut saglayicilar arasinda Test Store secenegini bulun. Test Store tum RevenueCat projelerine otomatik olarak saglandigi icin Create Test Store veya Enable Test Store'a tiklayarak etkinlestirmeniz yeterlidir. Kurulum onayi veya yapilandirma senkronizasyonu beklemenize gerek yoktur; aninda tamamlanir.
API Anahtarini Alma
Test Store etkinlestirildiginde, uygulama listesinde Test Store girişine tiklayarak ayrintilari kontrol edin. Burada test_ onekiyle baslayan Test Store API Key'i bulabilirsiniz. Bu anahtar normal RevenueCat API anahtari gibi calisir, ancak onemli bir fark vardir: tum satin alma isteklerini Google Play yerine Test Store'a yonlendirerek test ortami uzerinde tam kontrol saglar.
API Anahtari Ayrimini Anlama: Test Store API anahtari, production ve sandbox anahtarlarindan tamamen ayridir. Bu ayrim kasitli ve guvenlik acisindan onemlidir. Production build'lerde asla Test Store anahtarini kullanmayin; yalnizca debug ve test ortamlarinda kullanin. Gerekirse farkli test senaryolari icin proje basina birden fazla Test Store yapilandirmasi olusturabilirsiniz.
Sonraki adım
Artik Test Store API anahtarini aldiginiza gore, Android uygulamanizi test icin Test Store'u kullanacak sekilde yapilandirmaya hazirsiniz.
Android Uygulamada Test Store Kurulumu
0:05:00Simdi Android uygulamanizi Test Store'u kullanacak sekilde yapilandiracagiz. Onemli testleri calistirirken production API anahtari yerine Test Store API anahtarini kullanacaksiniz.
Adim 1: BuildConfig Alani Olusturma
Uygulamanizin build.gradle.kts dosyasina Test Store API anahtari yapilandirmasini ekleyin:
android {
defaultConfig {
// Your existing configuration
// Add Test Store API key for debug builds
buildConfigField("String", "REVENUECAT_TEST_STORE_API_KEY", "\"test_YOUR_KEY_HERE\"")
}
buildTypes {
debug {
// Use Test Store for debug builds
buildConfigField("String", "REVENUECAT_API_KEY", "\"test_YOUR_KEY_HERE\"")
}
release {
// Use production API key for release builds
buildConfigField("String", "REVENUECAT_API_KEY", "\"goog_YOUR_PRODUCTION_KEY\"")
}
}
}Adim 2: Test Store ile SDK Baslatma
Build turune gore uygun API anahtarini kullanmak icin Application sinifinizi guncelleyin:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Initialize RevenueCat SDK
val apiKey = BuildConfig.REVENUECAT_API_KEY
val builder = PurchasesConfiguration.Builder(this, apiKey)
Purchases.configure(
builder
.purchasesAreCompletedBy(PurchasesAreCompletedBy.REVENUECAT)
.appUserID(null)
.diagnosticsEnabled(true)
.build()
)
// Enable debug logs for test builds
if (BuildConfig.DEBUG) {
Purchases.logLevel = LogLevel.DEBUG
}
}
}Adim 3: Ortama Ozel Yapilandirma
Gelismis yapilandirma icin bir yapilandirma sinifi olusturabilirsiniz:
object RevenueCatConfig {
fun getApiKey(context: Context): String {
return if (isTestEnvironment()) {
BuildConfig.REVENUECAT_TEST_STORE_API_KEY
} else {
BuildConfig.REVENUECAT_API_KEY
}
}
private fun isTestEnvironment(): Boolean {
// Check if running in test environment
return try {
Class.forName("androidx.test.espresso.Espresso")
true
} catch (e: ClassNotFoundException) {
false
} || BuildConfig.DEBUG
}
}Ardindan baslatma sirasinda kullanin:
val apiKey = RevenueCatConfig.getApiKey(this)
Purchases.configure(
PurchasesConfiguration.Builder(this, apiKey)
.purchasesAreCompletedBy(PurchasesAreCompletedBy.REVENUECAT)
.build()
)doğrulama
Test Store'un calisip calismadigini dogrulamak icin:
- Uygulamayi debug modunda calistirin
- Gunluklerde
"Purchases SDK initialized with Test Store"mesajini kontrol edin - SDK'nin Google Play yerine Test Store'a baglandigini dogrulayin
Etkilesimli Satin Alma Akisi Testi
0:05:00Test Store etkinlestirildiginde, artik sonuclari tam olarak kontrol ederek satin alma akislarini test edebilirsiniz. Test Store satin alma iletisim kutusunu gosterdiginde sonucu siz belirlersiniz.
Test Store Satin Alma Iletisim Kutusunu Anlama
Test Store ile bir satin alma baslattiginizda, standart Google Play satin alma sayfasi yerine ozel bir Test Store iletisim kutusu gosterilir. Bu iletisim kutusu, gercek satin alma iletisim kutusu gibi urun ayrintilari ve fiyatlandirmayi gosterir, ancak onemli bir fark vardir: sonucu kontrol edebilirsiniz. Iletisim kutusu uc net secenek sunar: tamamlanmis islemi simule eden Successful Purchase, satin alma basarisizligini test eden Failed Purchase ve kullanici iptalini simule eden Cancel. Bu belirleyici davranis, Test Store'u test icin son derece guclu kilan seydir.
Basarili Akisi Test Etme
Basarili bir satin alma akisini test edelim:
suspend fun purchaseProduct(activity: Activity) {
try {
// Fetch products from Test Store
val products = Purchases.sharedInstance.awaitGetProducts(
productIds = listOf("premium_monthly")
)
// Initiate purchase
val purchaseResult = Purchases.sharedInstance.awaitPurchase(
purchaseParams = PurchaseParams.Builder(
activity = activity,
storeProduct = products.first()
).build()
)
// Check the result
val customerInfo = purchaseResult.customerInfo
val isPremium = customerInfo.entitlements["premium"]?.isActive == true
if (isPremium) {
// Purchase successful!
showPremiumContent()
}
} catch (e: PurchasesException) {
// Handle error
handlePurchaseError(e)
}
}Mutlu Yol Testi: Uygulamayi calistirin ve her zamanki gibi satin alma akisini baslatin. Test Store iletisim kutusu gorundigunde "Successful Purchase"'a dokunun. Uygulama aninda premium erisim vermeli ve yetkinin dogru guncellendigini dogrulayabilirsiniz. Bu sayede gercek odeme yontemi veya sandbox hesabi olmadan basarili akisin dogru calisip calismadigini hizlica kontrol edebilirsiniz.
Basarisiz Senaryolari Test Etme
Simdi uygulamanizin basarisizliklari nasil islemedigini test edin:
fun handlePurchaseError(error: PurchasesException) {
when (error.code) {
PurchasesErrorCode.PURCHASE_CANCELLED_ERROR -> {
// User cancelled - don't show error
Log.d("Purchase", "User cancelled purchase")
}
PurchasesErrorCode.PURCHASE_INVALID_ERROR -> {
// Invalid purchase
showError("This purchase is not available")
}
PurchasesErrorCode.PAYMENT_PENDING_ERROR -> {
// Payment pending (e.g., awaiting parental approval)
showPendingMessage()
}
else -> {
// Other errors
showError("Purchase failed: ${error.message}")
}
}
}Hata Isleme Testi: Satin alma akisini tekrar baslatin, ancak bu sefer Test Store iletisim kutusu gorundigunde "Failed Purchase"'a dokunun. Uygulama hatayi duygusuzca islemeli ve kullaniciya uygun bir hata mesaji gostermelidir. Kullanicinin premium erisim almadigini ve uygulamanin durumunun tutarli kaldigini dogrulayin. Bu, production'da hata isleme mantginizin dogru calisip calismadigini kontrol etmek icin onemlidir.
Iptali Test Etme
@Composable
fun PaywallScreen(onDismiss: () -> Unit) {
val scope = rememberCoroutineScope()
var isPurchasing by remember { mutableStateOf(false) }
Button(
onClick = {
scope.launch {
isPurchasing = true
try {
purchaseProduct(LocalContext.current as Activity)
} catch (e: PurchasesException) {
if (e.code == PurchasesErrorCode.PURCHASE_CANCELLED_ERROR) {
// User cancelled - just dismiss
onDismiss()
}
}
isPurchasing = false
}
},
enabled = !isPurchasing
) {
Text(if (isPurchasing) "Processing..." else "Subscribe")
}
}Kullanici Iptali Testi: Odeme duvarini acin ve abonelik butonuna dokunun. Test Store iletisim kutusu gorundigunde, satin almayi iptal eden bir kullaniciyi simule etmek icin "Cancel"'a dokunun. Odeme duvari hata mesaji gostermeden temiz bir sekilde kapanmalidir (iptal, bir hata durumu degil, normal bir kullanici eylemidir). Satin alma islemi kaydedilmedigini ve uygulamanin durumunun degismedigini dogrulayin.
Temel Cikarimlar
Test Store'un gucu belirleyici kontroldedir. Her satin alma girisiminde tam olarak ne olacagina siz karar verirsiniz. Bu, gercek odeme yontemi gerektirmeden veya sandbox hesaplarinin gecikmeleri ve karmasikliklarini yonetmeden dakikalar icinde tum senaryolari (basarili, basarisiz ve iptal) kapsamli bir sekilde test edebileceginiz anlamina gelir. Google Play ile entegre etmeye hazir oldugunuzda, satin alma mantginizin saglam olduguna dair tam bir guven duyabilirsiniz.
Otomatik Birim Testleri Yazma
0:08:00Test Store'un en guclu ozelliklerinden biri, uygulama ici satin alma mantigi icin otomatik birim testleri yazmanizi saglamasidir. CI/CD'de guvenilir bir sekilde calisan testler yazalim.
Adim 1: Test Bagimliklarini Ekleme
build.gradle.kts dosyasina asagidakileri ekleyin:
dependencies {
// RevenueCat SDK
implementation("com.revenuecat.purchases:purchases:9.20.2")
// Testing dependencies
testImplementation("junit:junit:4.13.2")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
testImplementation("io.mockk:mockk:1.13.8")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test:runner:1.5.2")
}Adim 2: Purchase Repository Olusturma
Oncelikle test edilebilir bir purchase repository olusturalim:
interface PurchaseRepository {
suspend fun getProducts(productIds: List<String>): List<StoreProduct>
suspend fun purchaseProduct(activity: Activity, product: StoreProduct): CustomerInfo
suspend fun getCustomerInfo(): CustomerInfo
}
class PurchaseRepositoryImpl(
private val purchases: Purchases = Purchases.sharedInstance
) : PurchaseRepository {
override suspend fun getProducts(productIds: List<String>): List<StoreProduct> {
return purchases.awaitGetProducts(productIds)
}
override suspend fun purchaseProduct(
activity: Activity,
product: StoreProduct
): CustomerInfo {
val result = purchases.awaitPurchase(
PurchaseParams.Builder(activity, product).build()
)
return result.customerInfo
}
override suspend fun getCustomerInfo(): CustomerInfo {
return purchases.awaitCustomerInfo()
}
}Adim 3: Is Mantigi Iceren View Model Olusturma
class PaywallViewModel(
private val repository: PurchaseRepository
) : ViewModel() {
private val _state = MutableStateFlow<PaywallState>(PaywallState.Loading)
val state: StateFlow<PaywallState> = _state.asStateFlow()
fun loadProducts() {
viewModelScope.launch {
try {
val products = repository.getProducts(listOf("premium_monthly"))
_state.value = PaywallState.Success(products)
} catch (e: Exception) {
_state.value = PaywallState.Error(e.message ?: "Unknown error")
}
}
}
fun purchaseProduct(activity: Activity, product: StoreProduct) {
viewModelScope.launch {
_state.value = PaywallState.Purchasing
try {
val customerInfo = repository.purchaseProduct(activity, product)
val isPremium = customerInfo.entitlements["premium"]?.isActive == true
if (isPremium) {
_state.value = PaywallState.PurchaseSuccess
} else {
_state.value = PaywallState.Error("Purchase completed but entitlement not active")
}
} catch (e: PurchasesException) {
when (e.code) {
PurchasesErrorCode.PURCHASE_CANCELLED_ERROR -> {
_state.value = PaywallState.PurchaseCancelled
}
else -> {
_state.value = PaywallState.Error(e.message)
}
}
}
}
}
}
sealed class PaywallState {
object Loading : PaywallState()
data class Success(val products: List<StoreProduct>) : PaywallState()
object Purchasing : PaywallState()
object PurchaseSuccess : PaywallState()
object PurchaseCancelled : PaywallState()
data class Error(val message: String) : PaywallState()
}Adim 4: Birim Testleri Yazma
Simdi Test Store'u kullanarak birim testleri olusturun:
@RunWith(AndroidJUnit4::class)
class PaywallViewModelTest {
private lateinit var repository: PurchaseRepository
private lateinit var viewModel: PaywallViewModel
@Before
fun setup() {
// Initialize RevenueCat with Test Store API key
Purchases.configure(
PurchasesConfiguration.Builder(
ApplicationProvider.getApplicationContext(),
"test_YOUR_KEY_HERE"
).build()
)
repository = PurchaseRepositoryImpl()
viewModel = PaywallViewModel(repository)
}
@Test
fun testLoadProducts_Success() = runTest {
// Given: ViewModel is initialized
// When: Loading products
viewModel.loadProducts()
// Wait for state to update
advanceUntilIdle()
// Then: Products should be loaded successfully
val state = viewModel.state.value
assertTrue(state is PaywallState.Success)
assertFalse((state as PaywallState.Success).products.isEmpty())
}
@Test
fun testPurchaseProduct_Success() = runTest {
// Given: Products are loaded
viewModel.loadProducts()
advanceUntilIdle()
val state = viewModel.state.value as PaywallState.Success
val product = state.products.first()
// When: User purchases product and Test Store dialog shows "Successful Purchase"
// Note: In actual test, you'll need to interact with Test Store dialog
viewModel.purchaseProduct(mockActivity, product)
advanceUntilIdle()
// Then: Purchase should succeed and entitlement should be active
val finalState = viewModel.state.value
assertTrue(finalState is PaywallState.PurchaseSuccess)
}
@Test
fun testPurchaseProduct_Cancelled() = runTest {
// Given: Products are loaded
viewModel.loadProducts()
advanceUntilIdle()
val state = viewModel.state.value as PaywallState.Success
val product = state.products.first()
// When: User cancels purchase in Test Store dialog
viewModel.purchaseProduct(mockActivity, product)
advanceUntilIdle()
// Then: State should indicate cancellation
val finalState = viewModel.state.value
assertTrue(finalState is PaywallState.PurchaseCancelled)
}
}Adim 5: Mock Tabanli Test Alternatifi
Daha fazla kontrol icin repository'yi mock'layabilirsiniz:
class PaywallViewModelMockTest {
private lateinit var mockRepository: PurchaseRepository
private lateinit var viewModel: PaywallViewModel
@Before
fun setup() {
mockRepository = mockk()
viewModel = PaywallViewModel(mockRepository)
}
@Test
fun testPurchaseSuccess() = runTest {
// Given: Mock successful purchase
val mockProduct = mockk<StoreProduct>()
val mockCustomerInfo = mockk<CustomerInfo> {
every { entitlements["premium"]?.isActive } returns true
}
coEvery {
mockRepository.purchaseProduct(any(), mockProduct)
} returns mockCustomerInfo
// When: Purchase is initiated
viewModel.purchaseProduct(mockk(), mockProduct)
advanceUntilIdle()
// Then: State should be success
assertTrue(viewModel.state.value is PaywallState.PurchaseSuccess)
}
@Test
fun testPurchaseFailed() = runTest {
// Given: Mock failed purchase
val mockProduct = mockk<StoreProduct>()
coEvery {
mockRepository.purchaseProduct(any(), mockProduct)
} throws PurchasesException(
PurchasesErrorCode.PAYMENT_PENDING_ERROR,
"Payment is pending"
)
// When: Purchase is initiated
viewModel.purchaseProduct(mockk(), mockProduct)
advanceUntilIdle()
// Then: State should show error
val state = viewModel.state.value
assertTrue(state is PaywallState.Error)
assertTrue((state as PaywallState.Error).message.contains("pending"))
}
}Bu Yaklasim Neden Calisiyor
Bu test yaklasimi, uygulama ici satin alma testinin geleneksel sorunlarini ortadan kaldirir. Test Store'a ag bagimliligi olmadigindan testler her seferinde guvenilir bir sekilde calisir. Artik baglanti sorunlari nedeniyle tutarsiz basarisizliklar yasamazsiniz. Testler dakikalar yerine saniyeler icinde calisarak gelistirme sirasinda hizli geri bildirim saglar. Gercek satin alma sistemleriyle yeniden uretmesi zor veya zaman alici uc durumlar dahil tum senaryolarda tam test kapsamini elde edebilirsiniz.
Olusturdugumuz mimari (is mantgini SDK'dan ayiran repository deseni kullanarak) bu testleri hizli ve bakimi kolay kilar. GitHub Actions gibi herhangi bir CI/CD ortaminda calistirabilirsiniz, boylece production'a ulasmadan once hatalari yakalayabilirsiniz.
CI/CD'de Testleri Calistirma
0:04:00Simdi testlerin GitHub Actions'da otomatik olarak calismasini ayarlayacagiz, boylece her kod degisikliginde satin alma mantigi tutarli bir sekilde korunur.
Adim 1: GitHub Actions Workflow Olusturma
.github/workflows/android-tests.yml dosyasini olusturun:
name: Android Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
test:
runs-on: ubuntu-latest
adım:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**__RCPH_0_HPRC__gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run unit tests
env:
REVENUECAT_TEST_STORE_API_KEY: ${{ secrets.REVENUECAT_TEST_STORE_API_KEY }}
run: ./gradlew testDebugUnitTest
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results
path: app/build/test-results/
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v3
with:
name: test-reports
path: app/build/reports/tests/Adim 2: GitHub Secrets'a Test Store API Anahtarini Ekleme
- GitHub repository'nize gidin
- Settings → Secrets and variables → Actions bolumune gidin
- New repository secret'a tiklayin
- Ad:
REVENUECAT_TEST_STORE_API_KEY - Deger: Test Store API anahtariniz (ornegin:
test_xxxxx) - Add secret'a tiklayin
Adim 3: Secret'i Kullanmak icin Gradle Yapilandirmasi
Ortam degiskenini kullanmak icin build.gradle.kts dosyasini guncelleyin:
android {
defaultConfig {
// Get Test Store API key from environment or use placeholder
val testStoreApiKey = System.getenv("REVENUECAT_TEST_STORE_API_KEY")
?: "test_placeholder"
buildConfigField("String", "REVENUECAT_TEST_STORE_API_KEY", "\"$testStoreApiKey\"")
}
}Adim 4: Emulator ile Instrumented Testleri Calistirma
Gelismis testler icin instrumented testler ekleyin:
instrumented-test:
runs-on: ubuntu-latest
adım:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Enable KVM (for faster emulator)
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run instrumented tests
uses: reactivecircus/android-emulator-runner@v2
env:
REVENUECAT_TEST_STORE_API_KEY: ${{ secrets.REVENUECAT_TEST_STORE_API_KEY }}
with:
api-level: 29
target: default
arch: x86_64
profile: Nexus 6
script: ./gradlew connectedDebugAndroidTest
- name: Upload instrumented test results
if: always()
uses: actions/upload-artifact@v3
with:
name: instrumented-test-results
path: app/build/outputs/androidTest-results/Kurulumu Dogrulama
Degisiklikleri commit ve push ederek workflow'u tetikleyin. Repository'nizin GitHub Actions sekmesine giderek testlerin otomatik olarak calistigini dogrulayin. Workflow kodu checkout ederken, ortami kurarken ve test paketini calistirirken gercek zamanli ilerlemeyi gorebilirsiniz. Birkac dakika icinde CI ortaminda tum testlerin gecip gecmedigini ogreneceksiniz.
Otomatik Testlerin Gucu
Bir kez kuruldugunada, her pull request birlestirilmeden once otomatik olarak dogrulanir. Bir degisiklik satin alma mantgini bozarsa aninda geri bildirim alirsiniz ve tum senaryolari manuel olarak test etmeniz gerekmez. Test Store, her calistirmada testlerin tutarli sonuclar uretmesini saglar ve tutarsiz testlerin hayal kirikligini ortadan kaldirir. Bu, hatali kodun main branch'e ulasmasini engelleyen bir kalite kapisi olusturur ve tekrarlayan manuel testlere harcanacak sayisiz saat tasarruf saglar.
En Iyi Uygulamalar ve Production Kurulumu
0:03:00Test Store'u kurdugunuza gore, simdi en iyi uygulamalari ve Test Store ile production ortami arasinda nasil gecis yapacaginizi ele alacagiz.
Ortam Ayirimi
Test Store ve production anahtarlarini her zaman ayri tutun:
object RevenueCatKeys {
// Test Store - for testing only
const val TEST_STORE_KEY = "test_xxxxx"
// Google Play - for production
const val GOOGLE_PLAY_KEY = "goog_xxxxx"
fun getApiKey(isTestMode: Boolean): String {
return if (isTestMode) TEST_STORE_KEY else GOOGLE_PLAY_KEY
}
}Build Variant kurulum
Build variant'lari kullanarak ortamlar arasinda otomatik gecisi uygulayin:
android {
buildTypes {
debug {
buildConfigField("String", "RC_API_KEY", "\"test_xxxxx\"")
buildConfigField("Boolean", "USE_TEST_STORE", "true")
}
release {
buildConfigField("String", "RC_API_KEY", "\"goog_xxxxx\"")
buildConfigField("Boolean", "USE_TEST_STORE", "false")
}
}
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
buildConfigField("String", "RC_API_KEY", "\"test_xxxxx\"")
}
create("staging") {
dimension = "environment"
buildConfigField("String", "RC_API_KEY", "\"test_xxxxx\"")
}
create("prod") {
dimension = "environment"
buildConfigField("String", "RC_API_KEY", "\"goog_xxxxx\"")
}
}
}Kapsamli Bir Test Stratejisi Olusturma
Uygulama ici satin almalar icin saglam bir test stratejisi piramit yaklasimini izlemelidir. Test Store kullanarak birim testleriyle baslayin ve satin alma mantgini izole olarak dogrulayin. Bunlar hizli calisir ve cogu sorunu erkenden yakalar. Bu temel uzerine, yine Test Store kullanan entegrasyon testleri olusturarak tam satin alma akisini uctan uca kontrol edin. Uygulamaniza guvendiginizde, platform entegrasyonunu kontrol etmek icin Google Play Sandbox ile manuel teste gecin. Son olarak, canli ortamda her seyin calistigini dogrulamak icin gercek satin almalarla kucuk olcekli production testleri yapin.
Test Store ve Sandbox Arasinda Secim Yapma
Erken gelistirme ve yineleme sirasinda Test Store en iyi seciminizdir. Satin alma akislarinin hizli prototiplenmesi, birim ve entegrasyon testleri yazma, hata isleme ve uc durum testleri icin mukemmeldir. Anlik geri bildirim dongusu, guvenilir ve hizli sonuclar gerektiren CI/CD otomatik testleri icin idealdir.
Test Store'un simule etmedigi platforma ozgu ozellikleri test etmeniz gerektiginde Google Play Sandbox'a gecin. Buna bekleyen islemler (ornegin ebeveyn onayi bekleme), makbuz dogrulama ayrintilari, abonelik yenileme donguleri ve bolgeleye ozgu fiyatlandirma dahildir. Sandbox'i production oncesi dogrulama ortami olarak dusuunun. Temel mantginizin saglam oldugunu bildiginizde ve Google Play entegrasyonunu kontrol etmeniz gerektiginde kullanin.
Guvenlik En Iyi Uygulamalari
Production'da asla Test Store API anahtarini ifsa etmeyin:
// ❌ BAD: Hardcoded keys
val apiKey = "test_xxxxx"
// ✅ GOOD: Environment-based configuration
val apiKey = if (BuildConfig.DEBUG) {
BuildConfig.TEST_STORE_API_KEY
} else {
BuildConfig.GOOGLE_PLAY_API_KEY
}
// ✅ BETTER: Check for test environment
val apiKey = when {
isRunningInTests() -> BuildConfig.TEST_STORE_API_KEY
BuildConfig.DEBUG -> BuildConfig.TEST_STORE_API_KEY
else -> BuildConfig.GOOGLE_PLAY_API_KEY
}Loglama ve Hata Ayiklama
Uygun loglama seviyelerini etkinlestirin:
if (BuildConfig.USE_TEST_STORE) {
Purchases.logLevel = LogLevel.VERBOSE
Log.d("RevenueCat", "Using Test Store for testing")
} else if (BuildConfig.DEBUG) {
Purchases.logLevel = LogLevel.DEBUG
} else {
Purchases.logLevel = LogLevel.INFO
}Production'a Gecis
Uygulamanizi yayinlamadan once kapsamli bir kontrol listesini tamamladiginizdan emin olun. Tum testler Test Store ile gecmeli ve Google Play Sandbox ile entegrasyon manuel olarak dogrulanmalidir. Build variant'larin her ortamda dogru API anahtarini kullanacak sekilde dogru yapilandirildigini tekrar kontrol edin. Production API anahtari guvenli tutulmali ve surum kontrolune commit edilmemelidir. Test Store anahtarinin release build'lerden tamamen kaldirildigini dogrulayin; yalnizca debug yapilandirmasinda bulunmalidir. Loglamanin uygun sekilde ayarlandigini kontrol edin (debug'da ayrintili, production'da minimum). Tum senaryolarda hata islemenin test edildigini dogrulayin.
Sonuç
Tebrikler! Android icin RevenueCat'in Test Store'unu basariyla kurdunuz. Bu codelab'de RevenueCat panelinde Test Store'u etkinlestirmeyi, Android uygulamanizda Test Store API anahtarini yapilandirmayi, belirleyici sonuclarla satin alma akislarini test etmeyi, satin alma mantigi icin otomatik birim testleri yazmayi, GitHub Actions gibi CI/CD ortamlarinda bu testleri calistirmayi ve ortam ayirimi icin en iyi uygulamalari ogrendiniz.
Temel Cikarimlar
Test Store, uygulama ici satin alma testine yaklasim sekilinizi temelden degistirir. Sandbox hesaplariyla ugrasma ve tutarsiz aga bagli testlerle bas etme gunleri geride kaldi. Satin alma sonuclari uzerinde belirleyici kontrol sayesinde uygulamaniza gercek guven veren guvenilir testler yazabilirsiniz. CI/CD entegrasyonu, her kod degisikliginde satin alma mantginin surekli dogrulandigini gosterir ve satin alma akislarini saatler yerine saniyeler icinde yineleyebilirsiniz. En onemlisi, satin almayla ilgili hatalari production'a ulasmadan once yakalayarak hem gelirinizi hem de kullanici deneyimini koruyabilirsiniz.
Sonraki Adimlar
Artik Test Store'u kurdugunuza gore, bu temel uzerine insa etme zamani. Tum satin alma senaryolarini kapsayan kapsamli testler yazarak baslayin; sadece mutlu yolu test etmeyin. Bu testleri CI/CD pipeline'iniza entegre edin, boylece her pull request'te otomatik olarak calisirlar. Uygulamanizin duzgun bir sekilde bozulup bozulmadigini kontrol etmek icin cesitli basarisizlik modlariyla hata islemeyi kapsamli bir sekilde test edin. Hazir oldugunuzda, abonelik yenilemeleri gibi seyleri kontrol etmek icin platforma ozgu testler icin Google Play Sandbox'a gecin. Son olarak, satin alma mantginizin her adimda kapsamli bir sekilde dogrulandigini bilerek guvenle yayinlayin.
Ek Kaynaklar
RevenueCat Test Store Blog Yazisi RevenueCat Android SDK Belgeleri Test Kilavuzu GitHub: Cat Paywall ComposeIyi testler!