تست کردن

Media3 آرتیفکت‌های آزمایشی اختصاصی (media3-test-utils و media3-test-utils-robolectric) را ارائه می‌دهد تا به شما کمک کند بازپخش رسانه، انتقال‌های حالت پخش‌کننده، مؤلفه‌های میانای کاربر، و منابع رسانه سفارشی را هم در آزمایش‌های JVM محلی و هم در آزمایش‌های ابزار دقیق دستگاه آزمایش کنید.

این صفحه روش‌های توصیه‌شده برای آزمایش برنامه‌هایی را که از ExoPlayer استفاده می‌کنند شرح می‌دهد و نحوه استفاده از ابزارهای کمکی آزمایشی Media3 را در هر محیط آزمایشی نشان می‌دهد.

توصیه‌های آزمایش

هنگام نوشتن آزمایش‌های خودکار برای بازپخش رسانه، این اصول اصلی را دنبال کنید:

  • ترجیح دادن مؤلفه‌های واقعی یا Media3 fakes بر mocks: از mocking Player یا ExoPlayer با چارچوب‌هایی مثل Mockito اجتناب کنید. Player دارای ثابت‌های حالت و قراردادهای شنونده است که تقلیدها اجرا نمی‌کنند، که می‌تواند آزمایش‌ها را شکننده کند یا اشکال‌ها را پنهان کند. درعوض، از یک نمونه واقعی ExoPlayer، FakePlayer، یا موارد جعلی مانند FakeMediaSource و FakeDataSource استفاده کنید. درصورت نیاز، برای درستی‌سنجی فراخوانی‌های بازگشت تماس سفارشی، از شبیه‌سازی استفاده کنید.
  • Wait deterministically instead of sleeping: ExoPlayer performs media loading and playback asynchronously on an internal thread. از تماس‌های دلخواه Thread.sleep که باعث کندی و ناپایداری آزمایش‌ها می‌شود اجتناب کنید. از TestPlayerRunHelper در آزمایش‌های Robolectric و تعلیق افزونه‌های Player یا PlayerFence در آزمایش‌های ابزار دقیق استفاده کنید. این کمک‌کننده‌ها منتظر شرایط صریح پخش‌کننده می‌مانند و اگر خطای بازپخش رخ دهد، فوراً ناموفق می‌شوند.
  • دسترسی به پخش‌کننده در رشته برنامه آن: نمونه‌های ExoPlayer و کمک‌کننده‌های منتظر باید در رشته برنامه پخش‌کننده Looper فراخوانی شوند (معمولاً رشته اصلی). برای اطلاعات بیشتر، الزامات رشته ExoPlayer را ببینید.

محیط آزمایشی مناسب را انتخاب کنید

لایه‌های مختلف ادغام رسانه شما از محیط‌های آزمایشی مختلف بهره می‌برند:

هدف آزمایشی محیط توصیه‌شده برنامه‌های کمکی کلیدی Media3
مؤلفه‌های میانای کاربر (PlayerView، Compose UI)،‏ ViewModels، یا بازخوان‌های MediaSession آزمایش‌های Robolectric محلی (src/test) یا آزمایش‌های واسط کاربر ابزاری (src/androidTest) FakePlayer
ادغام ExoPlayer، انتقال فهرست پخش، تجزیه‌وتحلیل، و منطق سفارشی MediaSource یا DataSource آزمایش‌های Robolectric محلی (src/test) TestExoPlayerBuilder، TestPlayerRunHelper، FakeMediaSource
رمزگشایی MediaCodec، پرداخت Surface، خروجی صوتی، و مدیریت حقوق دیجیتال سخت‌افزار واقعی آزمایش‌های ابزارگری در دستگاه‌های فیزیکی (src/androidTest) ExoPlayer.Builder، Player.await* افزونه، PlayerFence

درصورت امکان، آزمایش‌های بازپخش ابزار دقیق را به‌جای شبیه‌سازها در دستگاه‌های فیزیکی اجرا کنید، زیرا پیاده‌سازی‌های پشته رسانه شبیه‌ساز متفاوت است. برای اطلاعات بیشتر درباره پشتیبانی شبیه‌ساز، راهنمای دستگاه‌های پشتیبانی‌شده را ببینید.

افزودن وابستگی‌های آزمایشی

مصنوعات آزمایشی Media3 را بااستفاده از همان نسخه سایر ماژول‌های Media3 به بلوک dependencies فایل build.gradle.kts یا build.gradle ماژول خود اضافه کنید:

کاتلین

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"

این دو واحد مسئولیت‌ها را براساس محیط زمان اجرا تقسیم می‌کنند:

مطمئن شوید که واحد شما شامل وابستگی‌های چارچوب آزمون برای محیط‌های آزمون شما نیز باشد:

  • Robolectric: org.robolectric:robolectric. هنگام بار کردن دارایی‌های محلی، android.testOptions.unitTests.isIncludeAndroidResources = true را تنظیم کنید.
  • AndroidX Test: androidx.test:runner، androidx.test:core، و androidx.test.ext:junit.
  • روال‌های مشترک Kotlin در رشته اصلی: org.jetbrains.kotlinx:kotlinx-coroutines-android.

موافقت با میاناهای برنامه‌سازی کاربردی آزمایشی ناپایدار

کلاس‌ها و روش‌ها در media3-test-utils و media3-test-utils-robolectric با @UnstableApi حاشیه‌نویسی شده‌اند. اگرچه Media3 قصد دارد کمک‌کننده‌های آزمایشی پرکاربرد را در نسخه‌های مختلف ارگونومیک نگه دارد، اما ابزارهای آزمایشی از همان قوانین پایداری سازگاری دودویی مانند میاناهای برنامه‌سازی کاربردی بازپخش تولید پیروی نمی‌کنند.

در مجموعه‌های منبع آزمایشی، کلاس‌ها یا روش‌های آزمایشی را با @androidx.annotation.OptIn حاشیه‌نویسی کنید، برای بسته‌های آزمایشی‌تان package-info را اضافه کنید، یا lint.xml را برای منابع آزمایشی پیکربندی کنید. برای اطلاعات بیشتر، یادداشت‌های عیب‌یابی lint میانای برنامه‌سازی کاربردی ناپایدار را ببینید.

آزمایش‌های محلی با Robolectric

آزمایش‌های محلی Robolectric در JVM ماشین توسعه نرم‌افزار شما بدون دستگاه فیزیکی یا شبیه‌ساز اجرا می‌شوند. Robolectric پیاده‌سازی‌های MediaCodec را ارائه نمی‌دهد و Looper اصلی را تا زمانی که به‌طور صریح پمپ نشود، موقتاً متوقف نگه می‌دارد، بنابراین یک نمونه پیش‌فرض ExoPlayer نمی‌تواند رسانه را رمزگشایی کند یا به‌روزرسانی‌های وضعیت را به‌تنهایی ارائه دهد.

ساختن پخش‌کننده آزمایشی و بازپخش پیشرفته

از TestExoPlayerBuilder برای ایجاد ExoPlayer پیکربندی‌شده برای آزمایش‌های Robolectric استفاده کنید. به‌طور پیش‌فرض، TestExoPlayerBuilder عناصر زیر را پیکربندی می‌کند:

  • یک FakeClock (isAutoAdvancing = true) با پیشروی خودکار که پیشرفت زمان را بین رشته بازپخش پس‌زمینه ExoPlayer و Looper اصلی موقتاً متوقف‌شده Robolectric هماهنگ می‌کند.
  • پردازنده ویدیو و صدای جعلی (FakeVideoRenderer و FakeAudioRenderer) که نمونه‌های رسانه را براساس مُهر زمان آن‌ها بدون نیاز به رمزگشای MediaCodec مصرف می‌کنند.

برای پیش بردن بازپخش و ادعای نتایج در رشته اصلی (با پخش‌کننده‌ای که از Looper.getMainLooper، پیش‌فرض در Robolectric، استفاده می‌کند)، از روش‌های ایستا advance(player) یا play(player) در TestPlayerRunHelper استفاده کنید (play(player) پیش‌از انتظار، player.play را فراخوانی می‌کند). برای اکثر شرایط، کمک‌کننده Looper اصلی Robolectric را تا زمانی که شرط هدف برآورده شود پمپ می‌کند و اگر خطای بازپخش مهلک یا غیرمهلک رخ دهد، استثنایی ایجاد می‌کند:

کاتلین

@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 (یا PlayerRunResult وقتی Player ارسال می‌شود) را برمی‌گردانند. این انواع نتیجه روش‌هایی را برای انتظار در وضعیت‌های بازپخش، موقعیت‌ها، انتقال‌های فهرست پخش، فریم‌های رندرشده، فرمان‌های معلق، و خطاهای بازپخش موردانتظار، یا نادیده گرفتن خطاهای غیرمهلک ارائه می‌دهند. برای اطلاعات بیشتر درباره شرایط انتظار، به مرجع میانای برنامه‌سازی کاربردی TestPlayerRunHelper مراجعه کنید.

آزمایش با منابع جعلی و کدک‌های شبیه‌سازی‌شده

بسیاری از آزمایش‌های ادغام، پیمایش فهرست پخش، انتخاب قطعه، به‌روزرسانی‌های خط زمان، یا رفتار تکرار مجدد را درستی‌سنجی می‌کنند و به فایل‌های رسانه‌ای واقعی نیاز ندارند. می‌توانید خطوط زمان و داده‌های مصنوعی را بااستفاده از FakeMediaSource، FakeTimeline، FakeDataSource، یا WebServerDispatcher (با OkHttp MockWebServer) به پخش‌کننده TestExoPlayerBuilder وارد کنید:

کاتلین

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 نیاز دارد، کدک‌های شبیه‌سازی‌شده و ضبط برونداد را به‌صورت زیر پیکربندی کنید:

  1. withAllDefaultSupportedCodecs را از ShadowMediaCodecConfig به‌عنوان JUnit @Rule اضافه کنید تا کدک‌های شبیه‌سازی‌شده Robolectric ثبت شود.
  2. CapturingRenderersFactory ساخته‌شده با Clock (CapturingRenderersFactory(context, builder.getClock())) سازنده را به builder.setRenderersFactory ارسال کنید.
  3. هنگام آزمایش قطعه‌های ویدیو، یک Surface (مانند Surface(SurfaceTexture(1))) را با player.setVideoSurface پیوست کنید تا MediaCodecVideoRenderer فریم‌های رمزگشایی‌شده را به‌جای رد کردن، پردازش کند.
  4. برای درستی‌سنجی برونداد پردازش‌شده، قبل‌از شروع بازپخش، register(player, capturingRenderersFactory) را در PlaybackOutput فراخوانی کنید.
  5. پس‌از پایان بازپخش، پخش‌کننده و سطح را رها کنید و سپس خروجی قالب‌بندی‌شده از Dumper (Dumper().add(playbackOutput).toString()) را بررسی کنید.

آزمایش‌های ابزارگری در دستگاه‌ها

آزمایش‌های Robolectric محلی رمزگشاهای پلاتفرم واقعی، قطعه‌های صوتی، جلسه‌های DRM، یا رندر کردن Surface را اجرا نمی‌کنند. برای درستی‌سنجی رفتار بازپخش سرتاسر در دستگاه‌هایی که Android را اجرا می‌کنند، آزمایش‌های ابزاردار را در src/androidTest بااستفاده از ExoPlayer واقعی ساخته‌شده با ExoPlayer.Builder بنویسید.

در آزمایش‌های ابزار JUnit، روش‌های @Test به‌جای رشته اصلی برنامه، در رشته ابزار اجرا می‌شوند. همیشه ExoPlayer را در رشته برنامه Looper آن ایجاد، کنترل، و منتشر کنید، برای مثال بااستفاده از runBlocking(Dispatchers.Main) در Kotlin یا InstrumentationRegistry.getInstrumentation().runOnMainSync در Java.

منتظر ماندن برای وضعیت‌های بازیکن با PlayerFence و روال‌های هم‌زمان

در آزمایش‌های ابزار دقیق، Looper اصلی به‌طور هم‌زمان در دستگاه اجرا می‌شود. Robolectric یا media3-test-utils-robolectric را در وابستگی‌های androidTestImplementation اضافه نکنید. برای منتظر ماندن برای وضعیت‌ها و رویدادهای بازپخش، media3-test-utils کمک‌کننده‌های زیر را ارائه می‌دهد:

  • Kotlin: تعلیق توابع افزونه در Player (مانند awaitPlaybackState، awaitIsPlaying، awaitFirstFrameRendered، و awaitContentPositionAtLeast).
  • Java: روش ثابت futureWhen(player) در PlayerFence، که یک PlayerFence برمی‌گرداند که روش‌های شرط آن (مانند entersPlaybackState و isPlaying) باید در رشته Looper پخش‌کننده فراخوانی شوند و یک ListenableFuture برمی‌گرداند که رشته آزمایش می‌تواند با get در آن مسدود شود.

هر دو میانای برنامه‌سازی کاربردی بر بازیکن درحال انتظار نظارت می‌کنند. اگر خطای مهلک در بازپخش (یا به‌طور پیش‌فرض، خطای غیرمهلک) رخ دهد، یا اگر زمان انتظار از مهلت زمانی فراتر رود (به‌طور پیش‌فرض ۱۰ ثانیه، یا ۳۰ ثانیه در شبیه‌ساز)، تماس به‌جای قطع شدن، فوراً ناموفق می‌شود:

کاتلین

@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));
  }
}

When building ExoPlayer with ApplicationProvider.getApplicationContext in an app module (com.android.application), asset:/// URIs resolve against the target app's assets (such as src/debug/assets/ or src/main/assets/, rather than src/androidTest/assets/).

رویدادهای گذرا و نظارت سفارشی

علاوه‌بر بررسی وضعیت فعلی بازیکن (که در آن اگر شرط ازقبل برآورده شده باشد، انتظارها فوراً برمی‌گردند)، کمک‌کننده‌ها در media3-test-utils از رویدادهای یک‌باره و شرایط شنونده سفارشی پشتیبانی می‌کنند:

  • رویدادهای گذرا مانند اولین قاب پردازش‌شده: خروجی ویدیویی (مانند Surface یا PlayerView) را به پخش‌کننده متصل کنید و قبل‌از فراخوانی player.prepare، با awaitFirstFrameRendered یا rendersFirstFrame منتظر بمانید تا رویداد قاب یک‌باره اولیه ازدست نرود.
  • شرایط سفارشی: شنونده سفارشی یا انتظار روتین هم‌زمان را در awaitSupervised در player در Kotlin قرار دهید، یا ListenableFuture سفارشی را به futureWhen(player).withSupervision(future) در Java ارسال کنید. هنگام آزمایش بازیابی از خطاهای غیرکشنده، failOnNonFatalErrors = false (Kotlin) را ارسال کنید یا ignoringNonFatalErrors (Java) را فراخوانی کنید، و زمان‌های اتمام را با timeout یا withTimeoutMs(timeoutMs) سفارشی‌سازی کنید.

مثال زیر منتظر یک رویداد فریم اول گذرا می‌ماند و بر یک شنونده فراداده سفارشی نظارت می‌کند:

کاتلین

// 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

هنگام آزمایش کردن عناصر میانای کاربر مثل PlayerView یا media3-ui-compose composables،‏ ViewModels، یا MediaSession callbacks، ایجاد کردن ExoPlayer کامل اغلب غیرضروری است. ‫FakePlayer در media3-test-utils، SimpleBasePlayer را گسترش می‌دهد تا فهرست‌های پخش، وضعیت‌های بازپخش، موقعیت‌ها، اندازه‌های ویدیو، نشانه‌ها، و خطاهای موجود در Looper رشته فراخوان را شبیه‌سازی کند. این Looper به‌طور خودکار در آزمایش‌های Robolectric با @RunWith(AndroidJUnit4::class) و در رشته اصلی در آزمایش‌های ابزاردار دردسترس است.

به‌طور پیش‌فرض، FakePlayer تأخیر میان‌گیری ۱۰۰ میلی‌ثانیه‌ای را در prepare و seekTo شبیه‌سازی می‌کند؛ bufferingDelayMs = 0 را در Kotlin ارسال کنید یا وضعیت‌ها را مستقیماً با setPlaybackState تنظیم کنید:

کاتلین

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 در درخواست‌های محدوده، رسیدگی به خطا، و شنوندگان انتقال مطابقت دارند. برای اطلاعات بیشتر، ادغام کردن پشته‌های شبکه دیگر را ببینید.