Eşzamanlı yürütme işlemleri eşzamansız olabileceği ve birden fazla iş parçacığında gerçekleşebileceği için, eş yordamları kullanan birim testi kodları biraz daha dikkatli olmayı gerektirir. Bu kılavuzda, askıya alma işlevlerinin nasıl test edilebileceği, bilmeniz gereken test yapıları ve eş yordamların kullanıldığı kodunuzu nasıl test edilebilir hale getireceğiniz açıklanmaktadır.
Bu kılavuzda kullanılan API'ler kotlinx.coroutines.test kitaplığının bir parçasıdır. Bu API'lere erişebilmek için projenize bir test bağımlılığı olarak yapıyı eklediğinizden emin olun.
dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
}
Testlerde askıya alma işlevlerini çağırma
Testlerde askıya alma işlevlerini çağırmak için eş yordam içinde olmanız gerekir. JUnit test işlevlerinin kendisi askıya alınmadığından, yeni bir eş yordam başlatmak için testlerinizin içinde bir eş yordam oluşturucu çağırmanız gerekir.
runTest
, test için tasarlanmış bir eş yordam oluşturucudur. Eş yordam içeren tüm testleri sarmalamak için bunu kullanın. Eş yordamların yalnızca doğrudan test gövdesinde değil, aynı zamanda testte kullanılan nesneler tarafından da başlatılabileceğini unutmayın.
suspend fun fetchData(): String { delay(1000L) return "Hello world" } @Test fun dataShouldBeHelloWorld() = runTest { val data = fetchData() assertEquals("Hello world", data) }
Genel olarak, test başına bir runTest
çağrınız olmalıdır ve bir ifade gövdesi kullanmanız önerilir.
Testinizin kodunu runTest
içinde sarmalamak temel askıya alma işlevlerini test etmek için işe yarar ve eş yordamlardaki gecikmeleri otomatik olarak atlayarak yukarıdaki testin bir saniyeden çok daha hızlı tamamlanmasını sağlar.
Bununla birlikte, test edilen kodunuzda ne olduğuna bağlı olarak dikkate alınması gereken başka noktalar da vardır:
- Kodunuz,
runTest
tarafından oluşturulan üst düzey test koordini dışında yeni eş yordamlar oluşturduğunda, uygunTestDispatcher
öğesini seçerek bu yeni eş yordamların nasıl planlanacağını kontrol etmeniz gerekir. - Kodunuz, eş yordam yürütmeyi diğer sevk görevlilerine taşırsa (örneğin,
withContext
kullanarak)runTest
genellikle çalışmaya devam eder, ancak artık gecikmeler atlanmaz ve kod birden fazla iş parçacığında çalıştırıldığından testler daha az tahmin edilebilir olur. Bu nedenlerle, testlerde gerçek sevk görevlilerinin yerine test görev dağıtıcıları eklemeniz gerekir.
Test Görevlileri
TestDispatchers
, test amaçlı CoroutineDispatcher
uygulamalarıdır. Test sırasında yeni eş yordamlar oluşturulursa yeni eş yordamların yürütülmesini öngörülebilir hale getirmek için TestDispatchers
kullanmanız gerekir.
Kullanılabilir iki TestDispatcher
uygulaması vardır: StandardTestDispatcher
ve UnconfinedTestDispatcher
, yeni başlatılan eş yordamların farklı programlarını gerçekleştirir. Bu ikisi de sanal zamanı kontrol etmek ve testte çalışan eş yordamları yönetmek için bir TestCoroutineScheduler
kullanır.
Bir testte kullanılan yalnızca bir planlayıcı örneği olmalıdır ve tüm TestDispatchers
arasında paylaşılanlar olmalıdır. Paylaşım planlayıcıları hakkında bilgi edinmek için TestDispatcher Ekleme bölümüne bakın.
Üst düzey test koordinini başlatmak için runTest
, her zaman TestDispatcher
kullanacak olan bir CoroutineScope
uygulaması olan bir TestScope
oluşturur. Belirtilmezse TestScope
, varsayılan olarak bir StandardTestDispatcher
oluşturur ve üst düzey test koordinini çalıştırmak için bunu kullanır.
runTest
, TestScope
sevk görevlisi tarafından kullanılan planlayıcıda sıraya alınan eş yordamları takip eder ve ilgili planlayıcı üzerinde bekleyen çalışma olduğu sürece geri dönmez.
StandartTest Görevlisi
StandardTestDispatcher
üzerinde yeni eş yordamlar başlattığınızda, test iş parçacığının ücretsiz olduğu her durumda çalıştırılmak üzere temel planlayıcıda sıraya alınırlar. Bu yeni eş yordamların çalışmasına izin vermek için test iş parçacığını getirmeniz gerekir (diğer eş yordamların kullanılabilmesi için serbest bırakın). Bu sıraya alma davranışı, yeni eş yordamların test sırasında çalışma şekli üzerinde size hassas bir kontrol sağlar ve üretim kodundaki eş yordamların programlanmasına benzer.
Üst düzey test eş yordamının yürütülmesi sırasında test iş parçacığı hiç oluşturulmazsa yeni eş yordamlar yalnızca test eş yordamı tamamlandıktan sonra (ancak runTest
döndürmeden önce) çalışır:
@Test fun standardTest() = runTest { val userRepo = UserRepository() launch { userRepo.register("Alice") } launch { userRepo.register("Bob") } assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ❌ Fails }
Sıraya alınan eş yordamların çalışmasını sağlamak için test eş yordamını oluşturmanın çeşitli yolları vardır. Bu çağrıların tümü, geri dönmeden önce diğer eş yordamların test ileti dizisinde çalıştırılmasına izin verir:
advanceUntilIdle
: Sırada hiçbir şey kalmayıncaya kadar planlayıcıdaki diğer tüm eş yordamları çalıştırır. Bu, beklemedeki tüm eş yordamların çalıştırılmasına izin vermek için iyi bir varsayılan seçenektir ve çoğu test senaryosunda çalışır.advanceTimeBy
: Sanal zamanı belirli bir miktar kadar ilerletir ve bu noktadan önce çalışacak şekilde planlanmış eş yordamları sanal zamanda çalıştırır.runCurrent
: Geçerli sanal zamanda planlanmış eş yordamlar çalıştırır.
Önceki testi düzeltmek amacıyla advanceUntilIdle
, bekleyen iki eş yordamın onaylamaya devam etmeden önce işlerini yapmasına izin vermek için kullanılabilir:
@Test fun standardTest() = runTest { val userRepo = UserRepository() launch { userRepo.register("Alice") } launch { userRepo.register("Bob") } advanceUntilIdle() // Yields to perform the registrations assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ✅ Passes }
Serbest Test Görevlisi
UnconfinedTestDispatcher
üzerinde yeni eş yordamlar başlatıldığında, istekle mevcut ileti dizisinde başlatılır. Bu sayede, eş yordam oluşturucunun geri dönmesini beklemeden hemen çalışmaya başlayacaklar. Yeni eş yordamların çalıştırılmasına izin vermek için test iş parçacığını manuel olarak oluşturmanız gerekmediğinden çoğu durumda bu gönderme davranışı daha basit test koduyla sonuçlanır.
Ancak bu davranış, test dışı sevk görevlileriyle üretimde göreceğinizden farklıdır. Testiniz eşzamanlılığa odaklanıyorsa bunun yerine StandardTestDispatcher
özelliğini kullanmayı tercih edin.
Bu sevk görevlisini, varsayılan test yerine runTest
konumundaki üst düzey test eş yordamı için kullanmak istiyorsanız bir örnek oluşturun ve bunu parametre olarak iletin. Bu işlem, sevk görevlisini TestScope
kaynağından devraldığı için runTest
içinde oluşturulan yeni eş yordamların istekli bir şekilde yürütülmesini sağlar.
@Test fun unconfinedTest() = runTest(UnconfinedTestDispatcher()) { val userRepo = UserRepository() launch { userRepo.register("Alice") } launch { userRepo.register("Bob") } assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ✅ Passes }
Bu örnekte, lansman çağrıları yeni eş yordamlarını UnconfinedTestDispatcher
saatinde heyecanla başlatacaktır; yani her lansman çağrısı yalnızca kayıt tamamlandıktan sonra geri gelecektir.
UnconfinedTestDispatcher
adlı kanalın yeni eş yordamları heyecanla başlatacağını, ancak bu, onları da sabırsızlıkla tamamlayacağı anlamına gelmez. Yeni eş yordam askıya alınırsa diğer eş yordamlar yürütmeye devam eder.
Örneğin, bu testte kullanıma sunulan yeni eş yordam Aylin'i kaydeder ancak delay
çağrıldığında askıya alınır. Bu işlem, üst düzey koordinasyonun onaylamaya devam etmesini sağlar ve Bülent henüz kaydedilmemiş olduğundan test başarısız olur:
@Test fun yieldingTest() = runTest(UnconfinedTestDispatcher()) { val userRepo = UserRepository() launch { userRepo.register("Alice") delay(10L) userRepo.register("Bob") } assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ❌ Fails }
Test sevk görevlileri ekleme
Test edilen kod, ileti dizilerini değiştirmek (withContext
ile) veya yeni eş yordamlar başlatmak için sevk görevlilerini kullanabilir. Kod, paralel olarak birden fazla iş parçacığında yürütüldüğünde testler güvenilir olmayabilir. Onaylama işlemlerini doğru zamanda gerçekleştirmek veya kontrolünüzün olmadığı arka plan iş parçacıklarında çalışan görevlerin tamamlanmasını beklemek zor olabilir.
Testlerde, bu sevk görevlilerini TestDispatchers
örnekleriyle değiştirin. Bunun bazı avantajları vardır:
- Kod, tek test iş parçacığı üzerinde çalışarak testleri daha deterministik hale getirir
- Yeni eş yordamların nasıl planlanıp yürütüleceğini kontrol edebilirsiniz
- TestDispatcher araçları, gecikmeleri otomatik olarak atlayan ve manuel olarak ilerlemenizi sağlayan sanal zaman için bir planlayıcı kullanır.
Bağımlılık yerleştirme yöntemini kullanarak
görev dağıtıcıların yerini alacak gerçek sevk görevlilerini
testler. Bu örneklerde CoroutineDispatcher
ekleyeceğiz, ancak dilerseniz
en geniş kapsamlı ifade
CoroutineContext
Böylece testler sırasında daha da fazla esneklik elde edebilirsiniz.
Eş yordamların başlatıldığı sınıflara CoroutineScope
da ekleyebilirsiniz.
(Kapsam ekleme bölümünde açıklandığı gibi) ilgili görev dağıtıcı yerine
bölümüne ekleyin.
TestDispatchers
, örneklendirildiğinde varsayılan olarak yeni bir planlayıcı oluşturur. runTest
içinde TestScope
öğesinin testScheduler
özelliğine erişebilir ve bunu yeni oluşturulan TestDispatchers
öğelerine aktarabilirsiniz. Böylece sanal zamana dair anlayışları paylaşılacak ve advanceUntilIdle
gibi yöntemler, testin tamamlanması için tüm test görev dağıtıcılarında eş yordamlar çalıştırır.
Aşağıdaki örnekte, initialize
yönteminde IO
sevk aracını kullanarak yeni bir eş yordam oluşturan ve çağrıyı fetchData
yönteminde IO
sevk görevlisine geçiren bir Repository
sınıfı görebilirsiniz:
// Example class demonstrating dispatcher use cases class Repository(private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) { private val scope = CoroutineScope(ioDispatcher) val initialized = AtomicBoolean(false) // A function that starts a new coroutine on the IO dispatcher fun initialize() { scope.launch { initialized.set(true) } } // A suspending function that switches to the IO dispatcher suspend fun fetchData(): String = withContext(ioDispatcher) { require(initialized.get()) { "Repository should be initialized first" } delay(500L) "Hello world" } }
Testlerde, IO
sevk görevlisinin yerine bir TestDispatcher
uygulaması ekleyebilirsiniz.
Aşağıdaki örnekte, depoya StandardTestDispatcher
yerleştiriyoruz ve initialize
ürününde başlayan yeni eş yordamın devam etmeden önce tamamlandığından emin olmak için advanceUntilIdle
kodunu kullanıyoruz.
fetchData
, test iş parçacığında çalıştırılacağı ve test sırasında içerdiği gecikmeyi atlanacağı için TestDispatcher
üzerinde çalıştırmanın avantajlarından da faydalanır.
class RepositoryTest { @Test fun repoInitWorksAndDataIsHelloWorld() = runTest { val dispatcher = StandardTestDispatcher(testScheduler) val repository = Repository(dispatcher) repository.initialize() advanceUntilIdle() // Runs the new coroutine assertEquals(true, repository.initialized.get()) val data = repository.fetchData() // No thread switch, delay is skipped assertEquals("Hello world", data) } }
TestDispatcher
üzerinde başlatılan yeni eş yordamlar, yukarıda initialize
ile gösterildiği gibi manuel olarak gelişmiş olabilir. Bununla birlikte, üretim kodunda bunun mümkün veya istenen bir durum olmadığını unutmayın. Bunun yerine, bu yöntem askıya alınacak (sıralı yürütme için) veya bir Deferred
değeri döndürecek (eş zamanlı yürütme için) şekilde yeniden tasarlanmalıdır.
Örneğin, yeni bir koordinat başlatmak ve bir Deferred
oluşturmak için async
aracını kullanabilirsiniz:
class BetterRepository(private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) { private val scope = CoroutineScope(ioDispatcher) fun initialize() = scope.async { // ... } }
Böylece, hem testlerde hem de üretim kodunda bu kodu tamamladıktan sonra güvenle await
yapabilirsiniz:
@Test fun repoInitWorks() = runTest { val dispatcher = StandardTestDispatcher(testScheduler) val repository = BetterRepository(dispatcher) repository.initialize().await() // Suspends until the new coroutine is done assertEquals(true, repository.initialized.get()) // ... }
Eş yordamlar, planlayıcıyı paylaştığı bir TestDispatcher
üzerindeyse runTest
, geri dönmeden önce beklemedeki eş yordamların tamamlanmasını bekler. Ayrıca, diğer görev dağıtıcılarda olsalar bile üst düzey test eş yordamının alt öğeleri olan eş yordamları da bekler (dispatchTimeoutMs
parametresi tarafından belirtilen, varsayılan olarak 60 saniye olan bir zaman aşımına kadar).
Ana sevk görevlisini ayarlama
Yerel birim testlerinde, Android kullanıcı arayüzü iş parçacığını sarmalayan Main
görev dağıtıcısı, bu testler Android cihazda değil yerel bir JVM'de yürütüldüğünden kullanılamayacaktır. Test edilen kodunuz ana iş parçacığına referans veriyorsa birim testleri sırasında bir istisna oluşturur.
Bazı durumlarda, Main
sevk görevlisini diğer görev dağıtıcılarla aynı şekilde yerleştirebilirsiniz (önceki bölümde açıklandığı gibi). Böylece, testlerde onu bir TestDispatcher
ile değiştirebilirsiniz. Ancak, viewModelScope
gibi bazı API'ler arka planda sabit kodlu bir Main
görev dağıtıcısı kullanır.
Aşağıda, verileri yükleyen bir eş yordam başlatmak için viewModelScope
kullanan bir ViewModel
uygulaması örneği verilmiştir:
class HomeViewModel : ViewModel() { private val _message = MutableStateFlow("") val message: StateFlow<String> get() = _message fun loadMessage() { viewModelScope.launch { _message.value = "Greetings!" } } }
Main
sevk görevlisini her durumda TestDispatcher
ile değiştirmek için Dispatchers.setMain
ve Dispatchers.resetMain
işlevlerini kullanın.
class HomeViewModelTest { @Test fun settingMainDispatcher() = runTest { val testDispatcher = UnconfinedTestDispatcher(testScheduler) Dispatchers.setMain(testDispatcher) try { val viewModel = HomeViewModel() viewModel.loadMessage() // Uses testDispatcher, runs its coroutine eagerly assertEquals("Greetings!", viewModel.message.value) } finally { Dispatchers.resetMain() } } }
Main
sevk görevlisi bir TestDispatcher
ile değiştirildiyse yeni oluşturulan tüm TestDispatchers
, Main
görev dağıtıcısının planlayıcısını otomatik olarak kullanacaktır. Buna, runTest
tarafından oluşturulan StandardTestDispatcher
görev dahildir (başka bir görev dağıtıcı geçmiyorsa).
Bu, test sırasında yalnızca tek bir planlayıcının kullanılmasını kolaylaştırır. Bunun işe yaraması için Dispatchers.setMain
çağrısından sonra diğer tüm TestDispatcher
örneklerini oluşturduğunuzdan emin olun.
Her testte Main
sevk görevlisinin yerini alan kodun yinelenmesini önlemek için yaygın olarak kullanılan bir kalıp, kodu bir JUnit test kuralına ayıklamaktır:
// Reusable JUnit4 TestRule to override the Main dispatcher class MainDispatcherRule( val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), ) : TestWatcher() { override fun starting(description: Description) { Dispatchers.setMain(testDispatcher) } override fun finished(description: Description) { Dispatchers.resetMain() } } class HomeViewModelTestUsingRule { @get:Rule val mainDispatcherRule = MainDispatcherRule() @Test fun settingMainDispatcher() = runTest { // Uses Main’s scheduler val viewModel = HomeViewModel() viewModel.loadMessage() assertEquals("Greetings!", viewModel.message.value) } }
Bu kural uygulaması varsayılan olarak bir UnconfinedTestDispatcher
kullanır, ancak Main
sevk görevlisinin belirli bir test sınıfında hızlı bir şekilde yürütülmemesi gerekiyorsa parametre olarak StandardTestDispatcher
eklenebilir.
Test gövdesinde bir TestDispatcher
örneğine ihtiyaç duyduğunuzda, istenen türde olduğu sürece kuraldaki testDispatcher
öğesini yeniden kullanabilirsiniz. Testte kullanılan TestDispatcher
türünü açıkça belirtmek isterseniz veya Main
için kullanılandan farklı bir TestDispatcher
türüne ihtiyacınız varsa runTest
içinde yeni bir TestDispatcher
oluşturabilirsiniz. Main
sevk görevlisi TestDispatcher
olarak ayarlandığından, yeni oluşturulan her TestDispatchers
planlayıcısını otomatik olarak paylaşır.
class DispatcherTypesTest { @get:Rule val mainDispatcherRule = MainDispatcherRule() @Test fun injectingTestDispatchers() = runTest { // Uses Main’s scheduler // Use the UnconfinedTestDispatcher from the Main dispatcher val unconfinedRepo = Repository(mainDispatcherRule.testDispatcher) // Create a new StandardTestDispatcher (uses Main’s scheduler) val standardRepo = Repository(StandardTestDispatcher()) } }
Testin dışında sevk görevlileri oluşturma
Bazı durumlarda, test yönteminin dışında bir TestDispatcher
aracının kullanılabilir olması gerekebilir. Örneğin, test sınıfındaki bir özellik başlatılırken:
class Repository(private val ioDispatcher: CoroutineDispatcher) { /* ... */ } class RepositoryTestWithRule { private val repository = Repository(/* What TestDispatcher? */) @get:Rule val mainDispatcherRule = MainDispatcherRule() @Test fun someRepositoryTest() = runTest { // Test the repository... // ... } }
Main
sevk görevlisini önceki bölümde gösterildiği gibi değiştiriyorsanız Main
sevk görevlisi değiştirildikten sonra oluşturulan TestDispatchers
, planlayıcısını otomatik olarak paylaşır.
Ancak test sınıfının özellikleri olarak oluşturulan TestDispatchers
veya test sınıfındaki özelliklerin ilk kullanıma hazırlanması sırasında oluşturulan TestDispatchers
için bu durum geçerli değildir. Bunlar, Main
sevk görevlisi değiştirilmeden önce başlatılır. Bu nedenle yeni planlayıcılar oluştururlar.
Testinizde yalnızca bir planlayıcı olduğundan emin olmak için önce MainDispatcherRule
özelliğini oluşturun. Ardından, sınıf düzeyindeki diğer özelliklerin başlatıcılarında gerektiğinde sevk görevlisini (veya farklı türde bir TestDispatcher
öğesine ihtiyacınız varsa planlayıcısını) yeniden kullanın.
class RepositoryTestWithRule { @get:Rule val mainDispatcherRule = MainDispatcherRule() private val repository = Repository(mainDispatcherRule.testDispatcher) @Test fun someRepositoryTest() = runTest { // Takes scheduler from Main // Any TestDispatcher created here also takes the scheduler from Main val newTestDispatcher = StandardTestDispatcher() // Test the repository... } }
Testte oluşturulan runTest
ve TestDispatchers
işlemlerinin yine de Main
sevk görevlisinin planlayıcısını otomatik olarak paylaşacağını unutmayın.
Main
sevk görevlisini değiştirmiyorsanız sınıfın özelliği olarak ilk TestDispatcher
öğenizi (yeni bir planlayıcı oluşturur) oluşturun. Ardından, bu planlayıcıyı hem özellik olarak hem de test kapsamında her runTest
çağrısına ve oluşturulan her yeni TestDispatcher
öğesine manuel olarak iletin:
class RepositoryTest { // Creates the single test scheduler private val testDispatcher = UnconfinedTestDispatcher() private val repository = Repository(testDispatcher) @Test fun someRepositoryTest() = runTest(testDispatcher.scheduler) { // Take the scheduler from the TestScope val newTestDispatcher = UnconfinedTestDispatcher(this.testScheduler) // Or take the scheduler from the first dispatcher, they’re the same val anotherTestDispatcher = UnconfinedTestDispatcher(testDispatcher.scheduler) // Test the repository... } }
Bu örnekte, ilk sevk görevlisinin planlayıcısı runTest
adresine iletilir. Bu işlem, söz konusu planlayıcıyı kullanarak TestScope
için yeni bir StandardTestDispatcher
oluşturur. Ayrıca, sevk görevlisini doğrudan runTest
hattına geçerek ilgili sevk görevlisinde test eş yordamını çalıştırabilirsiniz.
Kendi TestScope'unuzu oluşturma
TestDispatchers
ürününde olduğu gibi, test gövdesinin dışında bir TestScope
öğesine erişmeniz gerekebilir. runTest
, arka planda otomatik olarak bir TestScope
oluştururken runTest
ile kullanmak üzere kendi TestScope
öğenizi de oluşturabilirsiniz.
Bu işlemi yaparken, oluşturduğunuz TestScope
üzerinde runTest
adlı kişiyi çağırdığınızdan emin olun:
class SimpleExampleTest { val testScope = TestScope() // Creates a StandardTestDispatcher @Test fun someTest() = testScope.runTest { // ... } }
Yukarıdaki kod, dolaylı olarak TestScope
için bir StandardTestDispatcher
ve yeni bir planlayıcı oluşturur. Bu nesnelerin tümü açıkça oluşturulabilir. Bu özellik, bağımlı ekleme kurulumlarıyla entegre etmeniz gerektiğinde yararlı olabilir.
class ExampleTest { val testScheduler = TestCoroutineScheduler() val testDispatcher = StandardTestDispatcher(testScheduler) val testScope = TestScope(testDispatcher) @Test fun someTest() = testScope.runTest { // ... } }
Kapsam yerleştirme
sırasında kontrol etmeniz gereken, eş yordamlar oluşturan bir sınıfınız varsa
söz konusu sınıfa eş yordamlı bir kapsam ekleyebilir, bunu
Testlerde TestScope
.
Aşağıdaki örnekte UserState
sınıfı bir UserRepository
öğesine bağlıdır
yeni kullanıcılar kaydettirmek ve kayıtlı kullanıcıların listesini getirmek için kullanılır. Bu çağrılar
UserRepository
işlevi, işlev çağrılarını askıya alıyor. UserState
, yerleştirilen
registerUser
işlevi içinde yeni bir eş yordam başlatmak için CoroutineScope
tuşuna basın.
class UserState( private val userRepository: UserRepository, private val scope: CoroutineScope, ) { private val _users = MutableStateFlow(emptyList<String>()) val users: StateFlow<List<String>> = _users.asStateFlow() fun registerUser(name: String) { scope.launch { userRepository.register(name) _users.update { userRepository.getAllUsers() } } } }
Bu sınıfı test etmek için, ders oluştururken runTest
sınıfından TestScope
notunu geçebilirsiniz.
UserState
nesnesi:
class UserStateTest { @Test fun addUserTest() = runTest { // this: TestScope val repository = FakeUserRepository() val userState = UserState(repository, scope = this) userState.registerUser("Mona") advanceUntilIdle() // Let the coroutine complete and changes propagate assertEquals(listOf("Mona"), userState.users.value) } }
Test işlevinin dışına, örneğin bir özellik olarak oluşturulan bir test için Kendi TestScope'unuzu oluşturma.