Media3 ডেডিকেটেড টেস্টিং আর্টিফ্যাক্ট (media3-test-utils এবং
media3-test-utils-robolectric) প্রদান করে যা আপনাকে লোকাল JVM টেস্ট
এবং ডিভাইস ইন্সট্রুমেন্টেশন টেস্ট, উভয় ক্ষেত্রেই মিডিয়া প্লেব্যাক, প্লেয়ার স্টেট
ট্রানজিশন, UI কম্পোনেন্ট এবং কাস্টম মিডিয়া সোর্স টেস্ট করতে সাহায্য করে।
এই পৃষ্ঠায় ExoPlayer ব্যবহার করে এমন অ্যাপ পরীক্ষা করার জন্য সাজেস্ট করা পদ্ধতিগুলি উল্লেখ করা হয়েছে
এবং প্রতিটি টেস্ট এনভায়রনমেন্টে Media3-এর টেস্টিং ইউটিলিটি কীভাবে ব্যবহার করতে হয় তা দেখানো হয়েছে।
সাজেশন পরীক্ষা করা হচ্ছে
মিডিয়া প্লেব্যাকের জন্য অটোমেটেড টেস্ট লেখার সময়, এইসব মূল নীতি অনুসরণ করুন:
- মকের পরিবর্তে আসল কম্পোনেন্ট বা Media3 ফেক ব্যবহার করা: Mockito-র মতো ফ্রেমওয়ার্কের সাহায্যে
PlayerবাExoPlayerমক করা এড়িয়ে চলুন।Player-এ স্টেট ইনভেরিয়েন্ট ও লিসনার কন্ট্র্যাক্ট আছে যা মক এনফোর্স করে না, এর ফলে টেস্ট ভঙ্গুর হতে পারে বা বাগ লুকিয়ে থাকতে পারে। পরিবর্তে, আসলExoPlayerইনস্ট্যান্স,FakePlayer, অথবা নকল যেমনFakeMediaSourceএবংFakeDataSourceব্যবহার করুন। প্রয়োজন হলে কাস্টম কলব্যাক ইনভোকেশন যাচাই করার জন্য মক রিজার্ভ করুন। - স্লিপিংয়ের পরিবর্তে নির্ধারকভাবে অপেক্ষা করুন:
ExoPlayerইন্টার্নাল থ্রেডে অ্যাসিঙ্ক্রোনাসভাবে মিডিয়া লোডিং ও প্লেব্যাক পারফর্ম করে। যথেচ্ছThread.sleepকল এড়িয়ে চলুন, যা টেস্টকে ধীর ও অবিশ্বস্ত করে তোলে। Robolectric টেস্টেTestPlayerRunHelperএবং ইনস্ট্রুমেন্টেশন টেস্টেPlayerএক্সটেনশন বাPlayerFenceসাসপেন্ড করা ব্যবহার করুন। এইসব হেল্পার প্লেয়ারের নির্দিষ্ট অবস্থার জন্য অপেক্ষা করে এবং প্লেব্যাক সংক্রান্ত কোনও সমস্যা হলে সাথে সাথে ব্যর্থ হয়। - অ্যাপ্লিকেশন থ্রেডে প্লেয়ার অ্যাক্সেস করুন:
ExoPlayerইনস্ট্যান্স এবং অপেক্ষারত হেল্পারদের অবশ্যই প্লেয়ারের অ্যাপ্লিকেশনLooperথ্রেডে কল করতে হবে (সাধারণত প্রধান থ্রেড)। আরও তথ্যের জন্য, ExoPlayer থ্রেডিং সংক্রান্ত প্রয়োজনীয়তা দেখুন।
সঠিক টেস্ট এনভায়রনমেন্ট বেছে নিন
আপনার মিডিয়া ইন্টিগ্রেশনের বিভিন্ন লেয়ার বিভিন্ন টেস্ট এনভায়রনমেন্ট থেকে সুবিধা পায়:
| টেস্ট টার্গেট | সাজেস্ট করা এনভায়রনমেন্ট | প্রধান Media3 ইউটিলিটি |
|---|---|---|
UI কম্পোনেন্ট (PlayerView, Compose UI), ViewModels অথবা MediaSession কলব্যাক |
লোকাল Robolectric টেস্ট (src/test) বা ইনস্ট্রুমেন্টেড UI টেস্ট (src/androidTest) |
FakePlayer |
ExoPlayer ইন্টিগ্রেশন, প্লেলিস্ট ট্রানজিশন, অ্যানালিটিক্স এবং কাস্টম MediaSource বা DataSource লজিক |
স্থানীয় রোবোলেকট্রিক টেস্ট (src/test) |
TestExoPlayerBuilder, TestPlayerRunHelper, FakeMediaSource |
আসল হার্ডওয়্যার MediaCodec ডিকোডিং, Surface রেন্ডারিং, অডিও আউটপুট ও DRM |
ফিজিক্যাল ডিভাইসে ইন্সট্রুমেন্টেশন টেস্ট (src/androidTest) |
ExoPlayer.Builder, Player.await* এক্সটেনশন, PlayerFence |
সম্ভব হলে, এমুলেটরের পরিবর্তে ফিজিক্যাল ডিভাইসে ইনস্ট্রুমেন্টেশন প্লেব্যাক টেস্ট চালান, কারণ এমুলেটর মিডিয়া স্ট্যাক প্রয়োগের পদ্ধতি আলাদা হয়। এমুলেটর সাপোর্ট সম্পর্কে আরও জানতে, কাজ করে এমন ডিভাইসের গাইড দেখুন।
টেস্টিং ডিপেন্ডেন্সি যোগ করুন
আপনার অন্যান্য Media3 মডিউলের মতো একই ভার্সন ব্যবহার করে আপনার মডিউলের build.gradle.kts বা build.gradle ফাইলের dependencies ব্লকে Media3 টেস্ট আর্টিফ্যাক্ট যোগ করুন:
Kotlin
testImplementation("androidx.media3:media3-test-utils:1.11.1")
testImplementation("androidx.media3:media3-test-utils-robolectric:1.11.1")
androidTestImplementation("androidx.media3:media3-test-utils:1.11.1")
গ্ৰুভি
testImplementation "androidx.media3:media3-test-utils:1.11.1"
testImplementation "androidx.media3:media3-test-utils-robolectric:1.11.1"
androidTestImplementation "androidx.media3:media3-test-utils:1.11.1"
দুটি মডিউল রানটাইম এনভায়রনমেন্ট অনুযায়ী দায়িত্ব ভাগ করে নেয়:
media3-test-utils: লোকাল ও ইনস্ট্রুমেন্টেড টেস্ট, দুটির জন্যই ক্রস-এনভায়রনমেন্ট ইউটিলিটি, যার মধ্যেTestExoPlayerBuilder,PlayerFence(এবং KotlinPlayer.await*এক্সটেনশন),FakePlayer,FakeClock,FakeMediaSource,FakeDataSource,DataSourceContractTestএবংMedia3FlagsRuleঅন্তর্ভুক্ত।media3-test-utils-robolectric: লোকাল JVM-এ Robolectric টেস্টের জন্য ইউটিলিটি, যার মধ্যেTestPlayerRunHelper,RobolectricUtil,ShadowMediaCodecConfig,CapturingRenderersFactoryএবংPlaybackOutputঅন্তর্ভুক্ত।
আপনার মডিউলে টেস্ট এনভায়রনমেন্টের জন্য টেস্ট ফ্রেমওয়ার্ক ডিপেন্ডেন্সিও অন্তর্ভুক্ত আছে কিনা তা নিশ্চিত করুন:
- Robolectric:
org.robolectric:robolectric. লোকাল অ্যাসেট লোড করার সময়android.testOptions.unitTests.isIncludeAndroidResources = trueসেট করুন। - AndroidX Test:
androidx.test:runner,androidx.test:coreএবংandroidx.test.ext:junit। - মূল থ্রেডে Kotlin coroutines:
org.jetbrains.kotlinx:kotlinx-coroutines-android.
অস্থির টেস্টিং API-তে অপ্ট-ইন করুন
media3-test-utils এবং media3-test-utils-robolectric-এ ক্লাস এবং পদ্ধতিগুলি
@UnstableApi দিয়ে অ্যানোটেট করা হয়েছে। যদিও Media3-এর লক্ষ্য হল
ব্যাপকভাবে ব্যবহৃত টেস্ট হেল্পারকে রিলিজ জুড়ে এরগোনমিক রাখা, টেস্ট ইউটিলিটিগুলি
প্রোডাকশন প্লেব্যাক API-এর মতো একই বাইনারি কম্প্যাটিবিলিটি স্টেবিলিটি নিয়ম অনুসরণ করে না।
আপনার টেস্ট সোর্স সেটে, @androidx.annotation.OptIn-এর সাথে টেস্ট ক্লাস বা পদ্ধতি অ্যানোটেট করুন, আপনার টেস্ট প্যাকেজের জন্য package-info অপ্ট-ইন যোগ করুন অথবা টেস্ট সোর্সের জন্য lint.xml কনফিগার করুন। আরও তথ্যের জন্য,
অস্থির API লিন্ট সমস্যার সমাধান সংক্রান্ত নোট দেখুন।
Robolectric-এর মাধ্যমে লোকাল টেস্ট
লোকাল Robolectric টেস্ট আপনার ডেভেলপমেন্ট মেশিনের JVM-এ রান করে,
এতে কোনও ফিজিক্যাল ডিভাইস বা এমুলেটর থাকে না। Robolectric MediaCodec ইমপ্লিমেন্টেশন প্রদান করে না এবং এটি প্রধান Looper পজ করে রাখে যতক্ষণ না
স্পষ্টভাবে পাম্প করা হয়, তাই একটি ডিফল্ট ExoPlayer ইনস্ট্যান্স মিডিয়া ডিকোড করতে পারে না বা
নিজেই স্ট্যাটাস আপডেট প্রদান করতে পারে না।
একটি টেস্ট প্লেয়ার তৈরি করুন এবং প্লেব্যাক উন্নত করুন
Robolectric টেস্টের জন্য কনফিগার করা ExoPlayer তৈরি করতে
TestExoPlayerBuilder ব্যবহার করুন। সাধারণত, TestExoPlayerBuilder নিম্নলিখিত
কম্পোনেন্ট কনফিগার করে:
- একটি অটো-অ্যাডভান্সিং
FakeClock(isAutoAdvancing = true) যাExoPlayer-এর ব্যাকগ্রাউন্ড প্লেব্যাক থ্রেড এবং Robolectric-এর পজ করা প্রধানLooper-এর মধ্যে সময়ের অগ্রগতিকে কোঅর্ডিনেট করে। - নকল ভিডিও এবং অডিও রেন্ডারার (
FakeVideoRendererএবংFakeAudioRenderer) যাMediaCodecডিকোডার ছাড়াই তাদের টাইমস্ট্যাম্প অনুযায়ী মিডিয়া স্যাম্পেল ব্যবহার করে।
প্লেব্যাক প্রোগ্রেস করতে এবং মূল থ্রেডে ফলাফল অ্যাসার্ট করতে (
Looper.getMainLooper ব্যবহার করে প্লেয়ারের সাথে, Robolectric-এ ডিফল্ট),
TestPlayerRunHelper-এ স্ট্যাটিক
advance(player) বা play(player) পদ্ধতি ব্যবহার করুন (অপেক্ষা করার আগে play(player)
player.play কল করে)। বেশিরভাগ শর্তের জন্য, হেল্পার পাম্প
Robolectric-এর প্রধান Looper যতক্ষণ না টার্গেট শর্ত পূরণ হয় এবং একটি
ব্যতিক্রম দেখায় যদি একটি মারাত্মক বা মারাত্মক নয় এমন প্লেব্যাক ত্রুটি ঘটে:
Kotlin
@RunWith(AndroidJUnit4::class) @OptIn(UnstableApi::class) class PlaybackRobolectricTest { private lateinit var player: ExoPlayer @After fun tearDown() { if (::player.isInitialized) { player.release() } } @Test fun play_sampleMediaItem_reachesEndedState() { val context = ApplicationProvider.getApplicationContext<Context>() player = TestExoPlayerBuilder(context).build() player.setMediaItem(MediaItem.fromUri("asset:///media/mp4/sample.mp4")) player.prepare() play(player).untilState(Player.STATE_ENDED) assertThat(player.playbackState).isEqualTo(Player.STATE_ENDED) } }
জাভা
@RunWith(AndroidJUnit4.class) @OptIn(markerClass = UnstableApi.class) public static class PlaybackRobolectricTest { private @Nullable ExoPlayer player; @After public void tearDown() { if (player != null) { player.release(); } } @Test public void play_sampleMediaItem_reachesEndedState() throws Exception { Context context = ApplicationProvider.getApplicationContext(); player = new TestExoPlayerBuilder(context).build(); player.setMediaItem(MediaItem.fromUri("asset:///media/mp4/sample.mp4")); player.prepare(); play(player).untilState(Player.STATE_ENDED); assertThat(player.getPlaybackState()).isEqualTo(Player.STATE_ENDED); } }
এই উদাহরণে, asset:///media/mp4/sample.mp4 আপনার মডিউলের src/test/assets/ (বা src/main/assets/) ডিরেক্টরিতে
রাখা একটি স্যাম্পেল মিডিয়া ফাইলকে বোঝায়।
ExoPlayer রেফারেন্স পাস করা হলে, advance(player) এবং play(player)
ExoPlayerRunResult (অথবা
Player পাস করা হলে PlayerRunResult) রিটার্ন করে। এই ধরনের ফলাফল
প্লেব্যাক স্ট্যাটাস, পজিশন, প্লেলিস্ট
ট্রানজিশন, রেন্ডার করা ফ্রেম, বাকি থাকা কমান্ড এবং প্রত্যাশিত প্লেব্যাক সংক্রান্ত সমস্যার জন্য অপেক্ষা করা বা
মারাত্মক নয় এমন সমস্যা উপেক্ষা করার পদ্ধতি প্রদান করে। অপেক্ষার শর্ত সম্পর্কে আরও জানতে,
TestPlayerRunHelper API রেফারেন্স দেখুন।
জাল সোর্স এবং সিমুলেটেড কোডেক দিয়ে পরীক্ষা করুন
অনেক ইন্টিগ্রেশন টেস্ট প্লেলিস্ট নেভিগেশন, ট্র্যাক বেছে নেওয়া, টাইমলাইন
আপডেট বা আবার চেষ্টা করার আচরণ যাচাই করে এবং আসল মিডিয়া ফাইলের প্রয়োজন হয় না। আপনি
FakeMediaSource, FakeTimeline,
FakeDataSource, অথবা
WebServerDispatcher (OkHttp MockWebServer-এর সাথে) ব্যবহার করে
TestExoPlayerBuilder প্লেয়ারে সিন্থেটিক টাইমলাইন ও ডেটা ফিড করতে পারবেন:
Kotlin
val player = TestExoPlayerBuilder(context).build() val fakeMediaSource = FakeMediaSource(FakeTimeline(/* windowCount= */ 2)) player.setMediaSource(fakeMediaSource) player.prepare() play(player).untilMediaItemIndex(/* mediaItemIndex= */ 1) assertThat(player.currentMediaItemIndex).isEqualTo(1) player.release()
জাভা
ExoPlayer player = new TestExoPlayerBuilder(context).build(); FakeMediaSource fakeMediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 2)); player.setMediaSource(fakeMediaSource); player.prepare(); play(player).untilMediaItemIndex(/* mediaItemIndex= */ 1); assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); player.release();
TestExoPlayerBuilder সাধারণত ফেক রেন্ডারার ব্যবহার করে। আপনার Robolectric টেস্টের
পরিবর্তে MediaCodec ইন্টার্যাকশন প্রয়োজন হলে, সিমুলেটেড কোডেক ও আউটপুট
ক্যাপচার এইভাবে কনফিগার করুন:
- Robolectric-এর সিমুলেটেড কোডেক রেজিস্টার করতে
ShadowMediaCodecConfigথেকে JUnit@RuleহিসেবেwithAllDefaultSupportedCodecsযোগ করুন। - বিল্ডারের
Clock(CapturingRenderersFactory(context, builder.getClock())) দিয়ে তৈরি করাCapturingRenderersFactorybuilder.setRenderersFactory-এ পাস করুন। - ভিডিও ট্র্যাক পরীক্ষা করার সময়,
player.setVideoSurface-এর সাথেSurface(যেমনSurface(SurfaceTexture(1))) অ্যাটাচ করুন যাতেMediaCodecVideoRendererডিকোড করা ফ্রেমগুলি এড়িয়ে যাওয়ার পরিবর্তে রেন্ডার করে। - রেন্ডার করা আউটপুট যাচাই করতে, প্লেব্যাক শুরু করার আগে
PlaybackOutput-এregister(player, capturingRenderersFactory)কল করুন। - প্লেব্যাক শেষ হওয়ার পরে, প্লেয়ার ও সারফেস রিলিজ করুন এবং তারপরে
Dumper(Dumper().add(playbackOutput).toString()) থেকে ফর্ম্যাট করা আউটপুট পরীক্ষা করুন।
ডিভাইসে ইন্সট্রুমেন্টেশন টেস্ট
লোকাল Robolectric টেস্ট আসল প্ল্যাটফর্ম ডিকোডার, অডিও ট্র্যাক, DRM
সেশন বা Surface রেন্ডারিং এক্সিকিউট করে না। Android ডিভাইসে এন্ড-টু-এন্ড প্লেব্যাক আচরণ যাচাই করতে,
ExoPlayer.Builder দিয়ে তৈরি আসল ExoPlayer ব্যবহার করে
src/androidTest-এ ইনস্ট্রুমেন্টেড টেস্ট লিখুন।
JUnit ইন্সট্রুমেন্টেশন টেস্টে, @Test পদ্ধতিগুলি অ্যাপ্লিকেশনের প্রধান থ্রেডের পরিবর্তে একটি ইন্সট্রুমেন্টেশন থ্রেডে চলে। সবসময় ExoPlayer-এর অ্যাপ্লিকেশন Looper থ্রেডে এটি তৈরি, নিয়ন্ত্রণ ও
রিলিজ করুন, যেমন Kotlin-এ
runBlocking(Dispatchers.Main) বা Java-তে
InstrumentationRegistry.getInstrumentation().runOnMainSync ব্যবহার করে।
PlayerFence ও কোরুটিনের মাধ্যমে প্লেয়ারের স্ট্যাটাসের জন্য অপেক্ষা করা
ইনস্ট্রুমেন্টেশন টেস্টে, প্রধান Looper ডিভাইসে রিয়েল টাইমে চলে।
androidTestImplementation ডিপেন্ডেন্সিতে Robolectric বা media3-test-utils-robolectric অন্তর্ভুক্ত করবেন না। প্লেব্যাক স্ট্যাটাস ও ইভেন্টের জন্য অপেক্ষা করতে, media3-test-utils নিম্নলিখিত সাহায্যকারী প্রদান করে:
- Kotlin:
Player-এ এক্সটেনশন ফাংশন সাসপেন্ড করা (যেমনawaitPlaybackState,awaitIsPlaying,awaitFirstFrameRenderedএবংawaitContentPositionAtLeast)। - Java:
PlayerFence-এ স্ট্যাটিকfutureWhen(player)পদ্ধতি, যা এমন একটিPlayerFenceরিটার্ন করে যার কন্ডিশন পদ্ধতি (যেমনentersPlaybackStateএবংisPlaying) প্লেয়ারেরLooperথ্রেডে কল করতে হবে এবং এমন একটিListenableFutureরিটার্ন করতে হবে যা টেস্ট থ্রেডget-এর মাধ্যমে ব্লক করতে পারে।
অপেক্ষা করার সময় দুটি API-ই প্লেয়ারকে তত্ত্বাবধান করে। যদি কোনও মারাত্মক প্লেব্যাক ত্রুটি (বা, ডিফল্টরূপে, একটি অ-মারাত্মক ত্রুটি) ঘটে, বা যদি অপেক্ষা তার টাইমআউট অতিক্রম করে (ডিফল্টরূপে ১০ সেকেন্ড, বা এমুলেটরে ৩০ সেকেন্ড), কলটি হ্যাং হওয়ার পরিবর্তে অবিলম্বে ব্যর্থ হয়:
Kotlin
@RunWith(AndroidJUnit4::class) @OptIn(UnstableApi::class) class PlaybackInstrumentationTest { private lateinit var player: ExoPlayer @After fun tearDown() = runBlocking(Dispatchers.Main) { if (::player.isInitialized) { player.release() } } @Test fun play_sampleMediaItem_advancesAndEnds() = runBlocking(Dispatchers.Main) { val context = ApplicationProvider.getApplicationContext<Context>() player = ExoPlayer.Builder(context).build() player.setMediaItem(MediaItem.fromUri("asset:///media/mp4/sample.mp4")) player.prepare() player.play() player.awaitIsPlaying(true) player.awaitContentPositionAtLeast(500) player.awaitPlaybackState(Player.STATE_ENDED) assertThat(player.playbackState).isEqualTo(Player.STATE_ENDED) } }
জাভা
@RunWith(AndroidJUnit4.class) @OptIn(markerClass = UnstableApi.class) public static class PlaybackInstrumentationTest { private @Nullable ExoPlayer player; @After public void tearDown() { InstrumentationRegistry.getInstrumentation() .runOnMainSync(() -> { if (player != null) { player.release(); } }); } @Test public void play_sampleMediaItem_advancesAndEnds() throws Exception { SettableFuture<Void> playbackStarted = SettableFuture.create(); SettableFuture<Void> positionPassed = SettableFuture.create(); SettableFuture<Void> playbackEnded = SettableFuture.create(); InstrumentationRegistry.getInstrumentation() .runOnMainSync(() -> { Context context = ApplicationProvider.getApplicationContext(); player = new ExoPlayer.Builder(context).build(); player.setMediaItem(MediaItem.fromUri("asset:///media/mp4/sample.mp4")); playbackStarted.setFuture(futureWhen(player).isPlaying(true)); positionPassed.setFuture(futureWhen(player).passesContentPosition(500)); playbackEnded.setFuture(futureWhen(player).entersPlaybackState(Player.STATE_ENDED)); player.prepare(); player.play(); }); playbackStarted.get(); positionPassed.get(); playbackEnded.get(); InstrumentationRegistry.getInstrumentation() .runOnMainSync(() -> assertThat(player.getPlaybackState()).isEqualTo(Player.STATE_ENDED)); } }
অ্যাপ মডিউলে (com.android.application) ApplicationProvider.getApplicationContext-এর সাথে ExoPlayer তৈরি করার সময়,
asset:/// URI টার্গেট অ্যাপের অ্যাসেটের (যেমন src/debug/assets/ বা src/main/assets/,
src/androidTest/assets/-এর পরিবর্তে) সাথে মিলে যায়।
ক্ষণস্থায়ী ইভেন্ট ও কাস্টম তত্ত্বাবধান
প্লেয়ারের বর্তমান স্ট্যাটাস চেক করার পাশাপাশি (যেখানে শর্ত আগে থেকেই পূরণ হয়ে থাকলে
অপেক্ষা করার প্রয়োজন হয় না), media3-test-utils-এর হেল্পার
এককালীন ইভেন্ট ও কাস্টম লিসেনার শর্তের ক্ষেত্রে সহায়তা করে:
- প্রথম রেন্ডার করা ফ্রেমের মতো ট্রানজিয়েন্ট ইভেন্ট: প্লেয়ারে ভিডিও আউটপুট
(যেমন,
SurfaceবাPlayerView) অ্যাটাচ করুন এবংplayer.prepareকল করার আগেawaitFirstFrameRenderedবাrendersFirstFrame-এর সাথে অপেক্ষা করা শুরু করুন যাতে প্রথম দিকের ওয়ান-অফ ফ্রেম ইভেন্ট মিস না হয়। - কাস্টম শর্ত: Kotlin-এ
player-এরawaitSupervised-এর মধ্যে কাস্টম লিসেনার বা কোরুটিন ওয়েট র্যাপ করুন অথবা Java-তেfutureWhen(player).withSupervision(future)-এ কাস্টমListenableFutureপাস করুন। নন-ফেটাল সমস্যা থেকে রিকভারি টেস্ট করার সময়,failOnNonFatalErrors = false(Kotlin) পাস করুন বাignoringNonFatalErrors(Java) কল করুন এবংtimeoutবাwithTimeoutMs(timeoutMs)-এর মাধ্যমে টাইমআউট কাস্টমাইজ করুন।
নিম্নলিখিত উদাহরণটি একটি ট্রানজিয়েন্ট ফার্স্ট-ফ্রেম ইভেন্টের জন্য অপেক্ষা করে এবং একটি কাস্টম মেটাডেটা লিসনার তত্ত্বাবধান করে:
Kotlin
// Start awaiting transient events (with a video surface attached) before prepare(). coroutineScope { val firstFrameDeferred = async(start = CoroutineStart.UNDISPATCHED) { player.awaitFirstFrameRendered() } player.setMediaItem(mediaItem) player.prepare() player.play() firstFrameDeferred.await() } // Supervise a custom listener condition while still failing fast on player errors. val metadataTitle = player.awaitSupervised { player.mediaMetadata.title?.let { return@awaitSupervised it } val titleDeferred = CompletableDeferred<CharSequence>() val listener = object : Player.Listener { override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) { mediaMetadata.title?.let { titleDeferred.complete(it) } } } player.addListener(listener) try { titleDeferred.await() } finally { player.removeListener(listener) } }
জাভা
SettableFuture<Void> firstFrameFuture = SettableFuture.create(); SettableFuture<CharSequence> metadataTitleFuture = SettableFuture.create(); SettableFuture<CharSequence> supervisedTitleFuture = SettableFuture.create(); Player.Listener metadataListener = new Player.Listener() { @Override public void onMediaMetadataChanged(MediaMetadata mediaMetadata) { if (mediaMetadata.title != null) { metadataTitleFuture.set(mediaMetadata.title); } } }; try { InstrumentationRegistry.getInstrumentation() .runOnMainSync(() -> { // Register transient event fences (with a video surface attached) before prepare(). firstFrameFuture.setFuture(futureWhen(player).rendersFirstFrame()); // Supervise a custom ListenableFuture so player errors fail fast. player.addListener(metadataListener); supervisedTitleFuture.setFuture( futureWhen(player).withSupervision(metadataTitleFuture)); player.setMediaItem(mediaItem); if (player.getMediaMetadata().title != null) { metadataTitleFuture.set(player.getMediaMetadata().title); } player.prepare(); player.play(); }); firstFrameFuture.get(); CharSequence title = supervisedTitleFuture.get(); } finally { InstrumentationRegistry.getInstrumentation() .runOnMainSync(() -> { player.removeListener(metadataListener); firstFrameFuture.cancel(/* mayInterruptIfRunning= */ true); supervisedTitleFuture.cancel(/* mayInterruptIfRunning= */ true); }); }
FakePlayer-এর সাহায্যে UI ও অ্যাপ কম্পোনেন্ট টেস্ট করা
PlayerView বা media3-ui-compose কম্পোজেবল, ViewModels বা MediaSession কলব্যাকের মতো UI কম্পোনেন্ট টেস্ট করার সময়, সম্পূর্ণ ExoPlayer তৈরি করার প্রয়োজন হয় না। media3-test-utils-এ FakePlayer
SimpleBasePlayer-কে এক্সটেন্ড করে যাতে
কলিং থ্রেডের Looper-এ প্লেলিস্ট, প্লেব্যাক স্টেট, পজিশন, ভিডিও সাইজ, কিউ ও সমস্যা সিমুলেট করা যায়। এই Looper অটোমেটিক উপলভ্য হয়
@RunWith(AndroidJUnit4::class) সহ Robolectric টেস্টে এবং ইনস্ট্রুমেন্টেড টেস্টে
মেন থ্রেডে।
সাধারণত, FakePlayer, prepare এবং
seekTo-এ ১০০ মিলিসেকেন্ডের বাফারিং বিলম্ব সিমুলেট করে; Kotlin-এ bufferingDelayMs = 0 পাস করুন বা
setPlaybackState-এর মাধ্যমে সরাসরি স্ট্যাটাস সেট করুন:
Kotlin
val fakePlayer = FakePlayer(bufferingDelayMs = 0) fakePlayer.setMediaItem(MediaItem.fromUri("https://example.com/media.mp4")) fakePlayer.prepare() fakePlayer.play() assertThat(fakePlayer.isPlaying).isTrue() // Drive state transitions directly to test UI or session listeners. fakePlayer.setPosition(30_000) fakePlayer.setPlaybackState(Player.STATE_ENDED) fakePlayer.release()
জাভা
FakePlayer fakePlayer = new FakePlayer(); fakePlayer.setMediaItem(MediaItem.fromUri("https://example.com/media.mp4")); // Drive state transitions directly (prepare() simulates a 100 ms buffering delay by default). fakePlayer.setPlaybackState(Player.STATE_READY); fakePlayer.play(); assertThat(fakePlayer.isPlaying()).isTrue(); fakePlayer.setPosition(30_000); fakePlayer.setPlaybackState(Player.STATE_ENDED); fakePlayer.release();
অতিরিক্ত টেস্টিং ইউটিলিটি
media3-test-utils-এ অন্যান্য টেস্টিং পরিস্থিতির জন্য বিশেষ হেল্পার অন্তর্ভুক্ত:
- ফিচার ফ্ল্যাগ ও Canary মোড: প্রতিটি টেস্টের পরে ফ্ল্যাগ ওভাররাইড রিসেট করতে এবং ফ্ল্যাগ স্টেট জুড়ে প্যারামিটারাইজড টেস্ট রান করতে
Media3FlagsRule-এর সাথে@BindFlagও@BindCanaryModeএকসাথে ব্যবহার করুন। আরও তথ্যের জন্য, ফিচার ফ্ল্যাগ সহ পরীক্ষা করা দেখুন। - কাস্টম
DataSourceকন্ট্র্যাক্ট টেস্ট: সাবক্লাসDataSourceContractTestযাতে কাস্টমDataSourceবাHttpDataSourceপ্রয়োগ রেঞ্জ অনুরোধ, সমস্যা সমাধান ও ট্রান্সফার লিসনার জুড়ে Media3-এর কন্ট্র্যাক্ট প্রত্যাশা পূরণ করে কিনা তা যাচাই করা যায়। আরও তথ্যের জন্য, অন্য নেটওয়ার্ক স্ট্যাক ইন্টিগ্রেট করা দেখুন।