WorkManager จะให้
อาร์ติแฟกต์ work-testing
ซึ่งจะช่วยในการทดสอบผู้ปฏิบัติงาน
ตั้งค่า
หากต้องการใช้อาร์ติแฟกต์ work-testing
ให้เพิ่มเป็น androidTestImplementation
ทรัพยากร Dependency ใน build.gradle
ดึงดูด
dependencies { def work_version = "2.5.0" ... // optional - Test helpers androidTestImplementation "androidx.work:work-testing:$work_version" }
Kotlin
dependencies { val work_version = "2.4.0" ... // optional - Test helpers androidTestImplementation("androidx.work:work-testing:$work_version") }
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเพิ่มทรัพยากร Dependency ได้ที่ "การประกาศทรัพยากร Dependency" ในส่วน บันทึกประจำรุ่นของ WorkManager
แนวคิด
work-testing
จัดเตรียมการใช้งาน WorkManager แบบพิเศษสำหรับโหมดทดสอบ
ซึ่งเริ่มต้นโดยใช้
WorkManagerTestInitHelper
อาร์ติแฟกต์ work-testing
ยังมี
SynchronousExecutor
ซึ่งทำให้เขียนการทดสอบแบบซิงโครนัสได้ง่ายขึ้น โดยไม่ต้อง
จัดการกับเทรด ล็อก หรือสลักหลายชิ้น
ตัวอย่างวิธีใช้ชั้นเรียนทั้งหมดนี้ร่วมกัน
Kotlin
@RunWith(AndroidJUnit4::class) class BasicInstrumentationTest { @Before fun setup() { val context = InstrumentationRegistry.getTargetContext() val config = Configuration.Builder() .setMinimumLoggingLevel(Log.DEBUG) .setExecutor(SynchronousExecutor()) .build() // Initialize WorkManager for instrumentation tests. WorkManagerTestInitHelper.initializeTestWorkManager(context, config) } }
Java
@RunWith(AndroidJUnit4.class) public class BasicInstrumentationTest { @Before public void setup() { Context context = InstrumentationRegistry.getTargetContext(); Configuration config = new Configuration.Builder() .setMinimumLoggingLevel(Log.DEBUG) .setExecutor(new SynchronousExecutor()) .build(); // Initialize WorkManager for instrumentation tests. WorkManagerTestInitHelper.initializeTestWorkManager( context, config); } }
การทดสอบโครงสร้าง
เริ่มต้น WorkManager ในโหมดทดสอบแล้ว คุณจึงพร้อมทดสอบ ผู้ปฏิบัติงานของคุณ
สมมติว่าคุณมี EchoWorker
ซึ่งคาดว่าจะได้รับ inputData
บางส่วนและ
คัดลอก (เสียงสะท้อน) อินพุตไปยัง outputData
Kotlin
class EchoWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) { override fun doWork(): Result { return when(inputData.size()) { 0 - >Result.failure() else - >Result.success(inputData) } } }
Java
public class EchoWorker extends Worker { public EchoWorker(Context context, WorkerParameters parameters) { super(context, parameters); } @NonNull @Override public Result doWork() { Data input = getInputData(); if (input.size() == 0) { return Result.failure(); } else { return Result.success(input); } } }
การทดสอบพื้นฐาน
ด้านล่างคือการทดสอบการใช้เครื่องมือของ Android ที่ทดสอบ EchoWorker
องค์ประกอบหลัก
สรุปก็คือการทดสอบ EchoWorker
ในโหมดทดสอบนั้นคล้ายกับ
คุณจะใช้ EchoWorker
ในแอปพลิเคชันจริง
Kotlin
@Test @Throws(Exception::class) fun testSimpleEchoWorker() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = OneTimeWorkRequestBuilderE<choWorker(>) .setInputData(input) .build() val workManager = WorkManager.getInstance(applicationContext) // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).result.get() // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
Java
@Test public void testSimpleEchoWorker() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .build(); WorkManager workManager = WorkManager.getInstance(getApplicationContext()); // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).getResult().get(); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
มาลองเขียนการทดสอบกันอีกซึ่งจะช่วยให้แน่ใจว่าเมื่อ EchoWorker
ไม่ได้รับอินพุต
Result
ที่คาดไว้คือ Result.failure()
Kotlin
@Test @Throws(Exception::class) fun testEchoWorkerNoInput() { // Create request val request = OneTimeWorkRequestBuilderE<choWorker(>) .build() val workManager = WorkManager.getInstance(applicationContext) // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).result.get() // Get WorkInfo val workInfo = workManager.getWorkInfoById(request.id).get() // Assert assertThat(workInfo.state, `is`(WorkInfo.State.FAILED)) }
Java
@Test public void testEchoWorkerNoInput() throws Exception { // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .build(); WorkManager workManager = WorkManager.getInstance(getApplicationContext()); // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).getResult().get(); // Get WorkInfo WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.FAILED)); }
จำลองข้อจำกัด ความล่าช้า และงานที่เกิดขึ้นเป็นระยะ
WorkManagerTestInitHelper
จะแสดงอินสแตนซ์
TestDriver
ที่สามารถใช้ได้
เพื่อจำลองการหน่วงเวลาขั้นต้น ซึ่งเป็นสภาวะที่จุดยึด
ListenableWorker
อินสแตนซ์ และช่วงเวลาสำหรับ PeriodicWorkRequest
อินสแตนซ์
ความล่าช้าเริ่มต้นในการทดสอบ
ผู้ปฏิบัติงานอาจเกิดความล่าช้าในช่วงแรก หากต้องการทดสอบ EchoWorker
ด้วย initialDelay
แทนที่จะต้องรอ initialDelay
ในการทดสอบ คุณสามารถใช้
TestDriver
เพื่อทำเครื่องหมายการหน่วงเวลาแรกเริ่มของคำขอทำงานเป็น "พบแล้ว" โดยใช้
setInitialDelayMet
Kotlin
@Test @Throws(Exception::class) fun testWithInitialDelay() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = OneTimeWorkRequestBuilderE<choWorker(>) .setInputData(input) .setInitialDelay(10, TimeUnit.SECONDS) .build() val workManager = WorkManager.getInstance(getApplicationContext()) // Get the TestDriver val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue workManager.enqueue(request).result.get() // Tells the WorkManager test framework that initial delays are now met. testDriver.setInitialDelayMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
Java
@Test public void testWithInitialDelay() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .setInitialDelay(10, TimeUnit.SECONDS) .build(); WorkManager workManager = WorkManager.getInstance(myContext); // Get the TestDriver TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue workManager.enqueue(request).getResult().get(); // Tells the WorkManager test framework that initial delays are now met. testDriver.setInitialDelayMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
ข้อจำกัดในการทดสอบ
นอกจากนี้ยังสามารถใช้ TestDriver
เพื่อทำเครื่องหมายข้อจำกัดว่าเป็นไปตามด้วย
setAllConstraintsMet
ต่อไปนี้คือตัวอย่างวิธีทดสอบ Worker
มีข้อจำกัด
Kotlin
@Test @Throws(Exception::class) fun testWithConstraints() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() // Create request val request = OneTimeWorkRequestBuilderE<choWorker(>) .setInputData(input) .setConstraints(constraints) .build() val workManager = WorkManager.getInstance(myContext) val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue workManager.enqueue(request).result.get() // Tells the testing framework that all constraints are met. testDriver.setAllConstraintsMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
Java
@Test public void testWithConstraints() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Define constraints Constraints constraints = new Constraints.Builder() .setRequiresDeviceIdle(true) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .setConstraints(constraints) .build(); WorkManager workManager = WorkManager.getInstance(myContext); TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue workManager.enqueue(request).getResult().get(); // Tells the testing framework that all constraints are met. testDriver.setAllConstraintsMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
การทดสอบการทำงานเป็นระยะ
TestDriver
จะแสดง setPeriodDelayMet
ที่ใช้เพื่อ
บ่งบอกว่าช่วงเวลาสิ้นสุดลงแล้ว นี่คือตัวอย่างของ
กำลังใช้setPeriodDelayMet
อยู่
Kotlin
@Test @Throws(Exception::class) fun testPeriodicWork() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = PeriodicWorkRequestBuilderE<choWorker(>15, MINUTES) .setInputData(input) .build() val workManager = WorkManager.getInstance(myContext) val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue and wait for result. workManager.enqueue(request).result.get() // Tells the testing framework the period delay is met testDriver.setPeriodDelayMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() // Assert assertThat(workInfo.state, `is`(WorkInfo.State.ENQUEUED)) }
Java
@Test public void testPeriodicWork() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(EchoWorker.class, 15, MINUTES) .setInputData(input) .build(); WorkManager workManager = WorkManager.getInstance(myContext); TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue and wait for result. workManager.enqueue(request).getResult().get(); // Tells the testing framework the period delay is met testDriver.setPeriodDelayMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.ENQUEUED)); }