작업자 구현 테스트

WorkManager는 Worker, ListenableWorker, ListenableWorker 변형(CoroutineWorkerRxWorker) 테스트를 위한 API를 제공합니다.

Worker 테스트

다음과 같은 Worker가 있다고 가정해 보겠습니다.

Kotlin


class SleepWorker(context: Context, parameters: WorkerParameters) :
    Worker(context, parameters) {

    override fun doWork(): Result {
        // Sleep on a background thread.
        Thread.sleep(1000)
        return Result.success()
    }
}

Java


public class SleepWorker extends Worker {
    public SleepWorker(
            @NonNull Context context,
            @NonNull WorkerParameters workerParameters) {
        super(context, workerParameters);
    }

    @NonNull
    @Override
    public Result doWork() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) {
return Result.success();
        }
    }
}

Worker를 테스트하려면 TestWorkerBuilder를 사용할 수 있습니다. 이 빌더는 비즈니스 로직을 테스트할 목적으로 사용할 수 있는 Worker의 인스턴스를 빌드하는 데 유용합니다.

Kotlin


// Kotlin code uses the TestWorkerBuilder extension to build
// the Worker
@RunWith(AndroidJUnit4::class)
class SleepWorkerTest {
    private lateinit var context: Context
    private lateinit var executor: Executor

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
        executor = Executors.newSingleThreadExecutor()
    }

    @Test
    fun testSleepWorker() {
        val worker = TestWorkerBuilder<SleepWorker>(
            context = context,
            executor = executor
        ).build()

        val result = worker.doWork()
        assertThat(result, `is`(Result.success()))
    }
}

Java


@RunWith(AndroidJUnit4.class)
public class SleepWorkerJavaTest {
    private Context context;
    private Executor executor;

    @Before
    public void setUp() {
        context = ApplicationProvider.getApplicationContext();
        executor = Executors.newSingleThreadExecutor();
    }

    @Test
    public void testSleepWorker() {
        SleepWorker worker =
                (SleepWorker) TestWorkerBuilder.from(context,
                        SleepWorker.class,
                        executor)
                        .build();

        Result result = worker.doWork();
        assertThat(result, is(Result.success()));
    }
}

또한 TestWorkerBuilder를 사용하여 inputData 또는 runAttemptCount 같은 태그를 설정해 작업자 상태를 독립적으로 확인할 수 있습니다. SleepWorker가 Worker에 정의된 상수가 아닌 절전 모드 지속 시간을 입력 데이터로 취하는 경우를 예로 들어 보겠습니다.

Kotlin


class SleepWorker(context: Context, parameters: WorkerParameters) :
    Worker(context, parameters) {

    override fun doWork(): Result {
        // Sleep on a background thread.
        val sleepDuration = inputData.getLong(SLEEP_DURATION, 1000)
        Thread.sleep(sleepDuration)
        return Result.success()
    }

    companion object {
        const val SLEEP_DURATION = "SLEEP_DURATION"
    }
}

Java


public class SleepWorker extends Worker {
    public static final String SLEEP_DURATION = "SLEEP_DURATION";

    public SleepWorker(
            @NonNull Context context,
            @NonNull WorkerParameters workerParameters) {
        super(context, workerParameters);
    }

    @NonNull
    @Override
    public Result doWork() {
        try {
            long duration = getInputData().getLong(SLEEP_DURATION, 1000);
            Thread.sleep(duration);
        } catch (InterruptedException ignore) {
       return Result.success();
        }
    }
}

SleepWorkerTest에서 입력 데이터를 TestWorkerBuilder에 제공하여 SleepWorker의 요구사항을 충족할 수 있습니다.

Kotlin


// Kotlin code uses the TestWorkerBuilder extension to build
// the Worker
@RunWith(AndroidJUnit4::class)
class SleepWorkerTest {
    private lateinit var context: Context
    private lateinit var executor: Executor

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
        executor = Executors.newSingleThreadExecutor()
    }

    @Test
    fun testSleepWorker() {
        val worker = TestWorkerBuilder<SleepWorker>(
            context = context,
            executor = executor,
            inputData = workDataOf("SLEEP_DURATION" to 1000L)
        ).build()

        val result = worker.doWork()
        assertThat(result, `is`(Result.success()))
    }
}

Java


@RunWith(AndroidJUnit4.class)
public class SleepWorkerJavaTest {
    private Context context;
    private Executor executor;

    @Before
    public void setUp() {
        context = ApplicationProvider.getApplicationContext();
        executor = Executors.newSingleThreadExecutor();
    }

    @Test
    public void testSleepWorker() {
        Data inputData = new Data.Builder()
                .putLong("SLEEP_DURATION", 1000L)
                .build();

        SleepWorker worker =
                (SleepWorker) TestWorkerBuilder.from(context,
                        SleepWorker.class, executor)
                        .setInputData(inputData)
                        .build();

        Result result = worker.doWork();
        assertThat(result, is(Result.success()));
    }
}

TestWorkerBuilder API에 관한 자세한 내용은 TestWorkerBuilder의 슈퍼클래스인 TestListenableWorkerBuilder의 참조 페이지를 확인하세요.

ListenableWorker 및 변형 테스트

ListenableWorker 또는 변형(CoroutineWorkerRxWorker)을 테스트하려면 TestListenableWorkerBuilder를 사용합니다. TestWorkerBuilderTestListenableWorkerBuilder의 주요 차이점은 TestWorkerBuilderWorker를 실행하는 데 사용되는 백그라운드 Executor를 지정할 수 있는 반면 TestListenableWorkerBuilderListenableWorker 구현의 스레딩 로직을 사용한다는 점입니다.

예를 들어 다음과 같이 CoroutineWorker를 테스트해야 한다고 가정해 보겠습니다.

class SleepWorker(context: Context, parameters: WorkerParameters) :
    CoroutineWorker(context, parameters) {
    override suspend fun doWork(): Result {
        delay(1000L) // milliseconds
        return Result.success()
    }
}

SleepWorker를 테스트하기 위해 먼저 TestListenableWorkerBuilder를 사용하는 Worker 인스턴스를 만든 다음 코루틴 내에서 doWork 함수를 호출합니다.

@RunWith(AndroidJUnit4::class)
class SleepWorkerTest {
    private lateinit var context: Context

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
    }

    @Test
    fun testSleepWorker() {
        val worker = TestListenableWorkerBuilder<SleepWorker>(context).build()
        runBlocking {
            val result = worker.doWork()
            assertThat(result, `is`(Result.success()))
        }
    }
}

비동기식으로 실행되는 모든 코드가 병렬로 실행되도록 runBlocking이 테스트용 코루틴 빌더로 타당합니다.

TestListenableWorkerBuilderListenableWorker의 서브클래스를 처리할 수 있으므로 RxWorker 구현을 테스트하는 것은 CoroutineWorker 테스트와 유사합니다. 코루틴 대신 RxJava를 사용하는 SleepWorker 버전을 생각해 보세요.

Kotlin


class SleepWorker(
    context: Context,
    parameters: WorkerParameters
) : RxWorker(context, parameters) {
    override fun createWork(): Single<Result> {
        return Single.just(Result.success())
            .delay(1000L, TimeUnit.MILLISECONDS)
    }
}

Java


public class SleepWorker extends RxWorker {
    public SleepWorker(@NonNull Context appContext, 
@NonNull WorkerParameters workerParams) {
        super(appContext, workerParams);
    }

    @NonNull
    @Override
    public Single<Result> createWork() {
        return Single.just(Result.success())
                .delay(1000L, TimeUnit.MILLISECONDS);
    }
}

RxWorker를 테스트하는 SleepWorkerTest 버전은 CoroutineWorker를 테스트한 버전과 유사할 수 있습니다. 동일한 TestListenableWorkerBuilder를 사용하지만 이제는 RxWorkercreateWork 함수를 호출합니다. createWork는 작업자의 동작을 확인하는 데 사용할 수 있는 Single을 반환합니다. TestListenableWorkerBuilder는 스레딩 복잡성을 처리하고 작업자 코드를 병렬로 실행합니다.

Kotlin


@RunWith(AndroidJUnit4::class)
class SleepWorkerTest {
    private lateinit var context: Context

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
    }

    @Test
    fun testSleepWorker() {
        val worker = TestListenableWorkerBuilder<SleepWorker>(context).build()
        worker.createWork().subscribe { result ->
            assertThat(result, `is`(Result.success()))
        }
    }
}

Java


@RunWith(AndroidJUnit4.class)
public class SleepWorkerTest {
    private Context context;

    @Before
    public void setUp() {
        context = ApplicationProvider.getApplicationContext();
    }

    @Test
    public void testSleepWorker() {
        SleepWorker worker = TestListenableWorkerBuilder.from(context, SleepWorker.class)
                .build();
        worker.createWork().subscribe(result ->
                assertThat(result, is(Result.success())));
        }
}