Uygulamanızda Sayfalandırma kitaplığını kullanırken güçlü bir
test stratejisidir. Aşağıdaki gibi veri yükleme bileşenlerini test etmeniz gerekir:
PagingSource
ve
RemoteMediator
emin olmak için testler yapın. Ayrıca tüm müşterilere
Sayfalama uygulamanızdaki tüm bileşenlerin düzgün çalıştığını doğrulayın
bir arada kullanma imkanınız da var.
Bu kılavuzda, Sayfalama kitaplığının farklı uygulamanızın mimari katmanlarını ve nasıl yazacağınızı uçtan uca testler sunar.
Kullanıcı arayüzü katman testleri
Sayfalama kitaplığıyla getirilen veriler, kullanıcı arayüzünde şu şekilde tüketilir:
Flow<PagingData<Value>>
.
Kullanıcı arayüzündeki verilerin beklediğiniz gibi olduğunu doğrulamak amacıyla test yazmak için
paging-testing
bağımlılık.
Flow<PagingData<Value>>
öğesinde asSnapshot()
uzantısını içeriyor. Google
lambda alıcısında, alay kaydırmasına olanak tanıyan API'ler sunar
etkileşimleridir. Kaydırma tarafından üretilen standart bir List<Value>
döndürür.
bir sahte etkileşim modelidir. Bu şekilde, verilerinizin
bu etkileşimlerin oluşturduğu beklenen öğeleri içerir.
Bu, aşağıdaki snippet'te gösterilmektedir:
fun test_items_contain_one_to_ten() = runTest {
// Get the Flow of PagingData from the ViewModel under test
val items: Flow<PagingData<String>> = viewModel.items
val itemsSnapshot: List<String> = items.asSnapshot {
// Scroll to the 50th item in the list. This will also suspend till
// the prefetch requirement is met if there's one.
// It also suspends until all loading is complete.
scrollTo(index = 50)
}
// With the asSnapshot complete, you can now verify that the snapshot
// has the expected values
assertEquals(
expected = (0..50).map(Int::toString),
actual = itemsSnapshot
)
}
Alternatif olarak, aşağıdaki snippet'i içerir:
fun test_footer_is_visible() = runTest {
// Get the Flow of PagingData from the ViewModel under test
val items: Flow<PagingData<String>> = viewModel.items
val itemsSnapshot: List<String> = items.asSnapshot {
// Scroll till the footer is visible
appendScrollWhile { item: String -> item != "Footer" }
}
Dönüşümleri test etme
Uyguladığınız tüm dönüşümleri kapsayan birim testleri de yazmanız gerekir.
PagingData
akışı. asPagingSourceFactory
kullanın
uzantısına sahip olur. Bu uzantı aşağıdaki veri türlerinde kullanılabilir:
List<Value>
.Flow<List<Value>>
.
Hangi uzantının kullanılacağı seçimi, neyi test etmeye çalıştığınıza bağlıdır. Şunu kullan:
List<Value>.asPagingSourceFactory()
: Statik öğeleri test etmek istiyorsanız dönüşümler (ör.map()
veinsertSeparators()
gibi)Flow<List<Value>>.asPagingSourceFactory()
: Güncellemelerin nasıl yedek veri kaynağına yazma gibi verileriniz sayfalamanızı etkiler ardışık düzendir.
Bu uzantılardan herhangi birini kullanmak için aşağıdaki şablonu izleyin:
- Size uygun uzantıyı kullanarak
PagingSourceFactory
gerekiyor. - Döndürülen
PagingSourceFactory
değerini şurada kullanın: sahteRepository
cihazınız için. Repository
hesabınıViewModel
cihazınıza iletin.
Ardından ViewModel
, önceki bölümde anlatıldığı şekilde test edilebilir.
Aşağıdaki ViewModel
göz önünde bulundurulmalıdır:
class MyViewModel(
myRepository: myRepository
) {
val items = Pager(
config: PagingConfig,
initialKey = null,
pagingSourceFactory = { myRepository.pagingSource() }
)
.flow
.map { pagingData ->
pagingData.insertSeparators<String, String> { before, _ ->
when {
// Add a dashed String separator if the prior item is a multiple of 10
before.last() == '0' -> "---------"
// Return null to avoid adding a separator between two items.
else -> null
}
}
}
MyViewModel
içindeki dönüşümü test etmek için sahte bir
Oluşturulacak verileri temsil eden statik bir List
öğesine yetki veren MyRepository
aşağıdaki snippet'te gösterildiği gibi dönüştürülür:
class FakeMyRepository(): MyRepository {
private val items = (0..100).map(Any::toString)
private val pagingSourceFactory = items.asPagingSourceFactory()
val pagingSource = pagingSourceFactory()
}
Ardından aşağıdaki snippet'te olduğu gibi ayırıcı mantığı için bir test yazabilirsiniz:
fun test_separators_are_added_every_10_items() = runTest {
// Create your ViewModel
val viewModel = MyViewModel(
myRepository = FakeMyRepository()
)
// Get the Flow of PagingData from the ViewModel with the separator transformations applied
val items: Flow<PagingData<String>> = viewModel.items
val snapshot: List<String> = items.asSnapshot()
// With the asSnapshot complete, you can now verify that the snapshot
// has the expected separators.
}
Veri katmanı testleri
Veri katmanınızdaki bileşenlere yönelik birim testleri yazarak
Veri kaynaklarınızdaki verileri uygun şekilde yükleyebilirsiniz. Sağlama
sahte versiyonları
teste tabi bileşenlerin doğru şekilde çalıştığını doğrulamak için bağımlılıkları
izole ediliyor. Depo katmanında test etmeniz gereken ana bileşenler
PagingSource
ve RemoteMediator
. İlerleyen bölümlerde yer alan örnekler,
Ağ ile Çağrı Yapma
Örnek.
PagingSource testleri
PagingSource
uygulamanız için birim testleri,
PagingSource
örneği ve bu örnekten veri TestPager
ile yükleme.
PagingSource
örneğini test etmek üzere ayarlamak için şuraya sahte veriler sağlayın:
kurucusu. Bu sayede testlerinizdeki veriler üzerinde kontrol sahibi olabilirsiniz.
Aşağıdaki örnekte, RedditApi
parametresi bir Retrofit
sunucu isteklerini ve yanıt sınıflarını tanımlayan bir arayüz oluşturur.
Sahte bir sürüm, arayüzü uygulayabilir, gerekli işlevleri geçersiz kılabilir,
ve sahte nesnenin nasıl tepki vermesi gerektiğini yapılandırmak için kolaylık yöntemleri sunar.
yardımcı olur.
Sahte öğeler uygulandıktan sonra bağımlılıkları ayarlayın ve
Testte PagingSource
nesne bulundu. Aşağıdaki örnekte,
FakeRedditApi
nesnesini test yayınları listesiyle başlatma ve test
RedditPagingSource
örneği:
class SubredditPagingSourceTest {
private val mockPosts = listOf(
postFactory.createRedditPost(DEFAULT_SUBREDDIT),
postFactory.createRedditPost(DEFAULT_SUBREDDIT),
postFactory.createRedditPost(DEFAULT_SUBREDDIT)
)
private val fakeApi = FakeRedditApi().apply {
mockPosts.forEach { post -> addPost(post) }
}
@Test
fun loadReturnsPageWhenOnSuccessfulLoadOfItemKeyedData() = runTest {
val pagingSource = RedditPagingSource(
fakeApi,
DEFAULT_SUBREDDIT
)
val pager = TestPager(CONFIG, pagingSource)
val result = pager.refresh() as LoadResult.Page
// Write assertions against the loaded data
assertThat(result.data)
.containsExactlyElementsIn(mockPosts)
.inOrder()
}
}
TestPager
, aşağıdakileri yapmanıza da olanak tanır:
PagingSource
cihazınızdan art arda yüklemeleri test edin:
@Test
fun test_consecutive_loads() = runTest {
val page = with(pager) {
refresh()
append()
append()
} as LoadResult.Page
assertThat(page.data)
.containsExactlyElementsIn(testPosts)
.inOrder()
}
PagingSource
içinde hata senaryolarını test edin:
@Test
fun refresh_returnError() {
val pagingSource = RedditPagingSource(
fakeApi,
DEFAULT_SUBREDDIT
)
// Configure your fake to return errors
fakeApi.setReturnsError()
val pager = TestPager(CONFIG, source)
runTest {
source.errorNextLoad = true
val result = pager.refresh()
assertTrue(result is LoadResult.Error)
val page = pager.getLastLoadedPage()
assertThat(page).isNull()
}
}
RemoteMediator testleri
RemoteMediator
birim testlerinin amacı, load()
işlevi doğru
MediatorResult
.
Veritabanına eklenen veriler gibi yan etki testleri,
entegrasyon testleri için daha uygundur.
İlk adım, RemoteMediator
metriğinizin hangi bağımlılıkları
bazı ipuçları vereceğim. Aşağıdaki örnekte RemoteMediator
gösterilmektedir
Oda veritabanı, Güçlendirme arayüzü ve arama gerektiren uygulama
dize:
Kotlin
@OptIn(ExperimentalPagingApi::class) class PageKeyedRemoteMediator( private val db: RedditDb, private val redditApi: RedditApi, private val subredditName: String ) : RemoteMediator<Int, RedditPost>() { ... }
Java
public class PageKeyedRemoteMediator extends RxRemoteMediator<Integer, RedditPost> { @NonNull private RedditDb db; @NonNull private RedditPostDao postDao; @NonNull private SubredditRemoteKeyDao remoteKeyDao; @NonNull private RedditApi redditApi; @NonNull private String subredditName; public PageKeyedRemoteMediator( @NonNull RedditDb db, @NonNull RedditApi redditApi, @NonNull String subredditName ) { this.db = db; this.postDao = db.posts(); this.remoteKeyDao = db.remoteKeys(); this.redditApi = redditApi; this.subredditName = subredditName; ... } }
Java
public class PageKeyedRemoteMediator extends ListenableFutureRemoteMediator<Integer, RedditPost> { @NonNull private RedditDb db; @NonNull private RedditPostDao postDao; @NonNull private SubredditRemoteKeyDao remoteKeyDao; @NonNull private RedditApi redditApi; @NonNull private String subredditName; @NonNull private Executor bgExecutor; public PageKeyedRemoteMediator( @NonNull RedditDb db, @NonNull RedditApi redditApi, @NonNull String subredditName, @NonNull Executor bgExecutor ) { this.db = db; this.postDao = db.posts(); this.remoteKeyDao = db.remoteKeys(); this.redditApi = redditApi; this.subredditName = subredditName; this.bgExecutor = bgExecutor; ... } }
Güçlendirme arayüzünü ve arama dizesini
PagingSource testleri bölümüne gidin. Modelin sürümünü sağlama
çok karmaşık bir süreçtir; bu nedenle her bir veri tabanının
bellek içi uygulanması
tam sürüm yerine veritabanını kullanabilirsiniz. Çünkü Oda veritabanı oluşturmak
Context
nesnesi gerektirirse
bu RemoteMediator
testini androidTest
dizinine yerleştirin ve yürütün
kullanarak bir test uygulamasına erişebilmesini sağlamak için
bağlam. Araçlı testler hakkında daha fazla bilgi için Araçlarlı testler derleme
birim testlerini kullanın.
Testler arasında durum sızıntısı olmaması için sökme fonksiyonlarını tanımlama işlevlerine dahildir. Bu yaklaşım, test çalıştırmaları arasında tutarlı sonuçlar sağlar.
Kotlin
@ExperimentalPagingApi @OptIn(ExperimentalCoroutinesApi::class) @RunWith(AndroidJUnit4::class) class PageKeyedRemoteMediatorTest { private val postFactory = PostFactory() private val mockPosts = listOf( postFactory.createRedditPost(SubRedditViewModel.DEFAULT_SUBREDDIT), postFactory.createRedditPost(SubRedditViewModel.DEFAULT_SUBREDDIT), postFactory.createRedditPost(SubRedditViewModel.DEFAULT_SUBREDDIT) ) private val mockApi = mockRedditApi() private val mockDb = RedditDb.create( ApplicationProvider.getApplicationContext(), useInMemory = true ) @After fun tearDown() { mockDb.clearAllTables() // Clear out failure message to default to the successful response. mockApi.failureMsg = null // Clear out posts after each test run. mockApi.clearPosts() } }
Java
@RunWith(AndroidJUnit4.class) public class PageKeyedRemoteMediatorTest { static PostFactory postFactory = new PostFactory(); static List<RedditPost> mockPosts = new ArrayList<>(); static MockRedditApi mockApi = new MockRedditApi(); private RedditDb mockDb = RedditDb.Companion.create( ApplicationProvider.getApplicationContext(), true ); static { for (int i=0; i<3; i++) { RedditPost post = postFactory.createRedditPost(DEFAULT_SUBREDDIT); mockPosts.add(post); } } @After public void tearDown() { mockDb.clearAllTables(); // Clear the failure message after each test run. mockApi.setFailureMsg(null); // Clear out posts after each test run. mockApi.clearPosts(); } }
Java
@RunWith(AndroidJUnit4.class) public class PageKeyedRemoteMediatorTest { static PostFactory postFactory = new PostFactory(); static List<RedditPost> mockPosts = new ArrayList<>(); static MockRedditApi mockApi = new MockRedditApi(); private RedditDb mockDb = RedditDb.Companion.create( ApplicationProvider.getApplicationContext(), true ); static { for (int i=0; i<3; i++) { RedditPost post = postFactory.createRedditPost(DEFAULT_SUBREDDIT); mockPosts.add(post); } } @After public void tearDown() { mockDb.clearAllTables(); // Clear the failure message after each test run. mockApi.setFailureMsg(null); // Clear out posts after each test run. mockApi.clearPosts(); } }
Bir sonraki adım, load()
işlevini test etmektir. Bu örnekte iki etkin
test edilecek durumlar:
- İlk durum,
mockApi
ürününün geçerli veriler döndürdüğü zamandır.load()
işleviMediatorResult.Success
veendOfPaginationReached
değerini döndürmelidir özelliğifalse
olmalıdır. - İkinci durum,
mockApi
adlı kullanıcının başarılı bir yanıt döndürmesi ancak döndürülen veriler boştur.load()
işlevi,MediatorResult.Success
veendOfPaginationReached
özelliğitrue
. - Üçüncü durum ise
mockApi
öğesinin veri getirirken istisna yapmasıdır.load()
işlevi,MediatorResult.Error
değerini döndürmelidir.
İlk durumu test etmek için aşağıdaki adımları uygulayın:
- Döndürülecek yayın verileriyle
mockApi
özelliğini ayarlayın. RemoteMediator
nesnesini başlatın.load()
işlevini test edin.
Kotlin
@Test fun refreshLoadReturnsSuccessResultWhenMoreDataIsPresent() = runTest { // Add mock results for the API to return. mockPosts.forEach { post -> mockApi.addPost(post) } val remoteMediator = PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT ) val pagingState = PagingState<Int, RedditPost>( listOf(), null, PagingConfig(10), 10 ) val result = remoteMediator.load(LoadType.REFRESH, pagingState) assertTrue { result is MediatorResult.Success } assertFalse { (result as MediatorResult.Success).endOfPaginationReached } }
Java
@Test public void refreshLoadReturnsSuccessResultWhenMoreDataIsPresent() throws InterruptedException { // Add mock results for the API to return. for (RedditPost post: mockPosts) { mockApi.addPost(post); } PageKeyedRemoteMediator remoteMediator = new PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT ); PagingState<Integer, RedditPost> pagingState = new PagingState<>( new ArrayList(), null, new PagingConfig(10), 10 ); remoteMediator.loadSingle(LoadType.REFRESH, pagingState) .test() .await() .assertValueCount(1) .assertValue(value -> value instanceof RemoteMediator.MediatorResult.Success && ((RemoteMediator.MediatorResult.Success) value).endOfPaginationReached() == false); }
Java
@Test public void refreshLoadReturnsSuccessResultWhenMoreDataIsPresent() throws InterruptedException, ExecutionException { // Add mock results for the API to return. for (RedditPost post: mockPosts) { mockApi.addPost(post); } PageKeyedRemoteMediator remoteMediator = new PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT, new CurrentThreadExecutor() ); PagingState<Integer, RedditPost> pagingState = new PagingState<>( new ArrayList(), null, new PagingConfig(10), 10 ); RemoteMediator.MediatorResult result = remoteMediator.loadFuture(LoadType.REFRESH, pagingState).get(); assertThat(result, instanceOf(RemoteMediator.MediatorResult.Success.class)); assertFalse(((RemoteMediator.MediatorResult.Success) result).endOfPaginationReached()); }
İkinci test, mockApi
işlevinin boş sonuç döndürmesini gerektirir. Çünkü siz
her test çalıştırmasından sonra mockApi
verilerini temizlediğinde boş bir değer döndürecektir
varsayılan olarak
belirlemenize olanak tanır.
Kotlin
@Test fun refreshLoadSuccessAndEndOfPaginationWhenNoMoreData() = runTest { // To test endOfPaginationReached, don't set up the mockApi to return post // data here. val remoteMediator = PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT ) val pagingState = PagingState<Int, RedditPost>( listOf(), null, PagingConfig(10), 10 ) val result = remoteMediator.load(LoadType.REFRESH, pagingState) assertTrue { result is MediatorResult.Success } assertTrue { (result as MediatorResult.Success).endOfPaginationReached } }
Java
@Test public void refreshLoadSuccessAndEndOfPaginationWhenNoMoreData() throws InterruptedException() { // To test endOfPaginationReached, don't set up the mockApi to return post // data here. PageKeyedRemoteMediator remoteMediator = new PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT ); PagingState<Integer, RedditPost> pagingState = new PagingState<>( new ArrayList(), null, new PagingConfig(10), 10 ); remoteMediator.loadSingle(LoadType.REFRESH, pagingState) .test() .await() .assertValueCount(1) .assertValue(value -> value instanceof RemoteMediator.MediatorResult.Success && ((RemoteMediator.MediatorResult.Success) value).endOfPaginationReached() == true); }
Java
@Test public void refreshLoadSuccessAndEndOfPaginationWhenNoMoreData() throws InterruptedException, ExecutionException { // To test endOfPaginationReached, don't set up the mockApi to return post // data here. PageKeyedRemoteMediator remoteMediator = new PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT, new CurrentThreadExecutor() ); PagingState<Integer, RedditPost> pagingState = new PagingState<>( new ArrayList(), null, new PagingConfig(10), 10 ); RemoteMediator.MediatorResult result = remoteMediator.loadFuture(LoadType.REFRESH, pagingState).get(); assertThat(result, instanceOf(RemoteMediator.MediatorResult.Success.class)); assertTrue(((RemoteMediator.MediatorResult.Success) result).endOfPaginationReached()); }
Son testte, testin yapılabilmesi için mockApi
öğesinin bir istisna yapması gerekir.
load()
işlevinin MediatorResult.Error
değerini doğru şekilde döndürdüğünü doğrulayın.
Kotlin
@Test fun refreshLoadReturnsErrorResultWhenErrorOccurs() = runTest { // Set up failure message to throw exception from the mock API. mockApi.failureMsg = "Throw test failure" val remoteMediator = PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT ) val pagingState = PagingState<Int, RedditPost>( listOf(), null, PagingConfig(10), 10 ) val result = remoteMediator.load(LoadType.REFRESH, pagingState) assertTrue {result is MediatorResult.Error } }
Java
@Test public void refreshLoadReturnsErrorResultWhenErrorOccurs() throws InterruptedException { // Set up failure message to throw exception from the mock API. mockApi.setFailureMsg("Throw test failure"); PageKeyedRemoteMediator remoteMediator = new PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT ); PagingState<Integer, RedditPost> pagingState = new PagingState<>( new ArrayList(), null, new PagingConfig(10), 10 ); remoteMediator.loadSingle(LoadType.REFRESH, pagingState) .test() .await() .assertValueCount(1) .assertValue(value -> value instanceof RemoteMediator.MediatorResult.Error); }
Java
@Test public void refreshLoadReturnsErrorResultWhenErrorOccurs() throws InterruptedException, ExecutionException { // Set up failure message to throw exception from the mock API. mockApi.setFailureMsg("Throw test failure"); PageKeyedRemoteMediator remoteMediator = new PageKeyedRemoteMediator( mockDb, mockApi, SubRedditViewModel.DEFAULT_SUBREDDIT, new CurrentThreadExecutor() ); PagingState<Integer, RedditPost> pagingState = new PagingState<>( new ArrayList(), null, new PagingConfig(10), 10 ); RemoteMediator.MediatorResult result = remoteMediator.loadFuture(LoadType.REFRESH, pagingState).get(); assertThat(result, instanceOf(RemoteMediator.MediatorResult.Error.class)); }
Uçtan uca testler
Birim testleri, bağımsız Sayfalandırma bileşenlerinin uçtan uca testler de uygulamanızın kullanıcı deneyimine bir bütün olarak çalışır. Bu testler için bazı örnek bağımlılıklar gerekli olacaktır ancak genellikle uygulama kodunuzun büyük bölümünü kaplar.
Bu bölümdeki örnekte ağından yararlanırız. Örnek API, tutarlı bir test kümesi döndürecek şekilde yapılandırılmıştır Bu da testlerin tekrarlanabilir olmasına yol açar. Hangi bağımlılıklarla değiştireceğinize karar verin yaptıklarına, ne kadar tutarlı olduğuna, ne kadar tutarlı olduklarına ve testlerinizin doğruluk oranını bilmeniz önemlidir.
Kodunuzu, Google Haberler'deki uygulamanızın taklidiyle kolayca değiştirmenizi sağlayacak şekilde yazın ve bildirmeyi konuştuk. Aşağıdaki örnekte temel bir hizmet bulucu kullanılmaktadır etkili bir yoludur. ve gerektiğinde bağımlılıkları değiştirebilirsiniz. Daha büyük uygulamalarda, bağımlılık yerleştirme Hilt gibi bir kütüphane proje yönetiminde ve daha karmaşık bağımlılık grafikleri oluşturabilirsiniz.
Kotlin
class RedditActivityTest { companion object { private const val TEST_SUBREDDIT = "test" } private val postFactory = PostFactory() private val mockApi = MockRedditApi().apply { addPost(postFactory.createRedditPost(DEFAULT_SUBREDDIT)) addPost(postFactory.createRedditPost(TEST_SUBREDDIT)) addPost(postFactory.createRedditPost(TEST_SUBREDDIT)) } @Before fun init() { val app = ApplicationProvider.getApplicationContext<Application>() // Use a controlled service locator with a mock API. ServiceLocator.swap( object : DefaultServiceLocator(app = app, useInMemoryDb = true) { override fun getRedditApi(): RedditApi = mockApi } ) } }
Java
public class RedditActivityTest { public static final String TEST_SUBREDDIT = "test"; private static PostFactory postFactory = new PostFactory(); private static MockRedditApi mockApi = new MockRedditApi(); static { mockApi.addPost(postFactory.createRedditPost(DEFAULT_SUBREDDIT)); mockApi.addPost(postFactory.createRedditPost(TEST_SUBREDDIT)); mockApi.addPost(postFactory.createRedditPost(TEST_SUBREDDIT)); } @Before public void setup() { Application app = ApplicationProvider.getApplicationContext(); // Use a controlled service locator with a mock API. ServiceLocator.Companion.swap( new DefaultServiceLocator(app, true) { @NotNull @Override public RedditApi getRedditApi() { return mockApi; } } ); } }
Java
public class RedditActivityTest { public static final String TEST_SUBREDDIT = "test"; private static PostFactory postFactory = new PostFactory(); private static MockRedditApi mockApi = new MockRedditApi(); static { mockApi.addPost(postFactory.createRedditPost(DEFAULT_SUBREDDIT)); mockApi.addPost(postFactory.createRedditPost(TEST_SUBREDDIT)); mockApi.addPost(postFactory.createRedditPost(TEST_SUBREDDIT)); } @Before public void setup() { Application app = ApplicationProvider.getApplicationContext(); // Use a controlled service locator with a mock API. ServiceLocator.Companion.swap( new DefaultServiceLocator(app, true) { @NotNull @Override public RedditApi getRedditApi() { return mockApi; } } ); } }
Test yapısını oluşturduktan sonraki adım,
Pager
uygulaması doğru olduğunda. Tek bir test, projenizin
Pager
nesnesi, varsayılan verileri sayfa ilk yüklendiğinde yükler, başka bir öğe ise
test, Pager
nesnesinin temel alınan ek verileri doğru şekilde yüklediğini doğrulamalıdır
kullanıcı girişinde görebilirsiniz. Aşağıdaki örnekte test, Pager
nesne, RecyclerView.Adapter
öğesini doğru sayıda öğeyle günceller
kullanıcı arama yapmak için farklı bir alt reddit girdiğinde API'den döndürülür.
Kotlin
@Test fun loadsTheDefaultResults() { ActivityScenario.launch(RedditActivity::class.java) onView(withId(R.id.list)).check { view, noViewFoundException -> if (noViewFoundException != null) { throw noViewFoundException } val recyclerView = view as RecyclerView assertEquals(1, recyclerView.adapter?.itemCount) } } @Test // Verify that the default data is swapped out when the user searches for a // different subreddit. fun loadsTheTestResultsWhenSearchingForSubreddit() { ActivityScenario.launch(RedditActivity::class.java ) onView(withId(R.id.list)).check { view, noViewFoundException -> if (noViewFoundException != null) { throw noViewFoundException } val recyclerView = view as RecyclerView // Verify that it loads the default data first. assertEquals(1, recyclerView.adapter?.itemCount) } // Search for test subreddit instead of default to trigger new data load. onView(withId(R.id.input)).perform( replaceText(TEST_SUBREDDIT), pressKey(KeyEvent.KEYCODE_ENTER) ) onView(withId(R.id.list)).check { view, noViewFoundException -> if (noViewFoundException != null) { throw noViewFoundException } val recyclerView = view as RecyclerView assertEquals(2, recyclerView.adapter?.itemCount) } }
Java
@Test public void loadsTheDefaultResults() { ActivityScenario.launch(RedditActivity.class); onView(withId(R.id.list)).check((view, noViewFoundException) -> { if (noViewFoundException != null) { throw noViewFoundException; } RecyclerView recyclerView = (RecyclerView) view; assertEquals(1, recyclerView.getAdapter().getItemCount()); }); } @Test // Verify that the default data is swapped out when the user searches for a // different subreddit. public void loadsTheTestResultsWhenSearchingForSubreddit() { ActivityScenario.launch(RedditActivity.class); onView(withId(R.id.list)).check((view, noViewFoundException) -> { if (noViewFoundException != null) { throw noViewFoundException; } RecyclerView recyclerView = (RecyclerView) view; // Verify that it loads the default data first. assertEquals(1, recyclerView.getAdapter().getItemCount()); }); // Search for test subreddit instead of default to trigger new data load. onView(withId(R.id.input)).perform( replaceText(TEST_SUBREDDIT), pressKey(KeyEvent.KEYCODE_ENTER) ); onView(withId(R.id.list)).check((view, noViewFoundException) -> { if (noViewFoundException != null) { throw noViewFoundException; } RecyclerView recyclerView = (RecyclerView) view; assertEquals(2, recyclerView.getAdapter().getItemCount()); }); }
Java
@Test public void loadsTheDefaultResults() { ActivityScenario.launch(RedditActivity.class); onView(withId(R.id.list)).check((view, noViewFoundException) -> { if (noViewFoundException != null) { throw noViewFoundException; } RecyclerView recyclerView = (RecyclerView) view; assertEquals(1, recyclerView.getAdapter().getItemCount()); }); } @Test // Verify that the default data is swapped out when the user searches for a // different subreddit. public void loadsTheTestResultsWhenSearchingForSubreddit() { ActivityScenario.launch(RedditActivity.class); onView(withId(R.id.list)).check((view, noViewFoundException) -> { if (noViewFoundException != null) { throw noViewFoundException; } RecyclerView recyclerView = (RecyclerView) view; // Verify that it loads the default data first. assertEquals(1, recyclerView.getAdapter().getItemCount()); }); // Search for test subreddit instead of default to trigger new data load. onView(withId(R.id.input)).perform( replaceText(TEST_SUBREDDIT), pressKey(KeyEvent.KEYCODE_ENTER) ); onView(withId(R.id.list)).check((view, noViewFoundException) -> { if (noViewFoundException != null) { throw noViewFoundException; } RecyclerView recyclerView = (RecyclerView) view; assertEquals(2, recyclerView.getAdapter().getItemCount()); }); }
Araçlı testler, verilerin kullanıcı arayüzünde doğru şekilde görüntülendiğini doğrulamalıdır. Yapılması gerekenler
Bunu kontrol etmek için
RecyclerView.Adapter
veya her bir satırdaki görünüm ve
verilerin doğru biçimlendirildiğini doğrulayın.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Ağ ve veritabanındaki sayfa
- Sayfa 3'e geçme
- Sayfalandırılmış verileri yükleme ve görüntüleme