Как ввести несколько значений расширения в JUnit 5 с помощью ParameterResolver - PullRequest
2 голосов
/ 03 ноября 2019

Как можно ввести несколько значений в тест с использованием шаблона ParameterResolver?

Кажется, что можно определить только одно возвращаемое значение.

В настоящее время getStore сохраняет значение расширения, котороевводится как параметр, используя ParameterResolver. В этом примере это TestCoroutineDispatcher для управления жизненным циклом Coroutine в локальном тесте JUnit. Как насчет того, нужно ли вводить второе значение из того же расширения?

Реализация

Test.kt

@ExtendWith(LifecycleExtensions::class)
// The TestCoroutineDispatcher is injected here as a parameter.
class FeedLoadContentTests(val testDispatcher: TestCoroutineDispatcher) {

    private val contentViewModel = ContentViewModel()
    private fun FeedLoad() = feedLoadTestCases()

    @ParameterizedTest
    @MethodSource("FeedLoad")
    fun `Feed Load`(test: FeedLoadContentTest) = testDispatcher.runBlockingTest {
        // Some testing done here.
    }
}

Extension.kt

class LifecycleExtensions : BeforeAllCallback, AfterAllCallback, BeforeEachCallback,
        AfterEachCallback, ParameterResolver {
    ...

    override fun beforeEach(context: ExtensionContext?) {
        // Set Coroutine Dispatcher.
        Dispatchers.setMain(context?.getStore(STORE_NAMESPACE)
                ?.get(STORE_KEY, TestCoroutineDispatcher::class.java)!!)

        ...
    }

    override fun afterEach(context: ExtensionContext?) {
        // Reset Coroutine Dispatcher.
        Dispatchers.resetMain()
        context?.getStore(STORE_NAMESPACE)
                ?.get(STORE_KEY, TestCoroutineDispatcher::class.java)!!.cleanupTestCoroutines()

        ...
    }

    override fun supportsParameter(parameterContext: ParameterContext?,
                                   extensionContext: ExtensionContext?) =
            parameterContext?.parameter?.type == TestCoroutineDispatcher::class.java

    override fun resolveParameter(parameterContext: ParameterContext?,
                                  extensionContext: ExtensionContext?) =
            TestCoroutineDispatcher().apply {
                extensionContext?.getStore(STORE_NAMESPACE)?.put(STORE_KEY, this)
            }
}

1 Ответ

0 голосов
/ 07 ноября 2019

Спасибо за понимание @ Slaw !

Ну, и #supportsParameter, и #resolveParameter вызываются для каждого параметра в методе. Таким образом, у вас есть тест, чтобы увидеть, является ли тип параметра TestCoroutineDispatcher, что означает, что вы можете добавить тест для общего типа ViewModel. Затем разрешите правильный параметр в зависимости от типа. Если вы хотите использовать ViewModel в нескольких тестах, вы можете сохранить ссылку на него в родительском / корневом ExtensionContext.Store.

Test.kt

@ExtendWith(LifecycleExtensions::class)
// The TestCoroutineDispatcher is injected here as a parameter.
class FeedLoadContentTests(val testDispatcher: TestCoroutineDispatcher, val contentViewModel: ContentViewModel) {

    private fun FeedLoad() = feedLoadTestCases()

    @ParameterizedTest
    @MethodSource("FeedLoad")
    // Injected testDispatcher used here.
    fun `Feed Load`(test: FeedLoadContentTest) = testDispatcher.runBlockingTest {
        // Some testing done here.
        // Injected contentViewModel used here.
    }
}

Extension.kt

class LifecycleExtensions : BeforeAllCallback, AfterAllCallback, BeforeEachCallback,
        AfterEachCallback, ParameterResolver {

    override fun beforeEach(context: ExtensionContext?) {
        // Set Coroutine Dispatcher.
        Dispatchers.setMain(context?.root
                ?.getStore(TEST_COROUTINE_DISPATCHER_NAMESPACE)
                ?.get(TEST_COROUTINE_DISPATCHER_KEY, TestCoroutineDispatcher::class.java)!!)

        // Set ViewModel
        context?.root
                ?.getStore(VIEWMODEL_NAMESPACE)
                ?.get(CONTENT_VIEWMODEL_KEY, ContentViewModel::class.java)!!

        // Set LiveData Executor.
        ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
            override fun executeOnDiskIO(runnable: Runnable) = runnable.run()
            override fun postToMainThread(runnable: Runnable) = runnable.run()
            override fun isMainThread(): Boolean = true
        })
    }

    override fun afterEach(context: ExtensionContext?) {
        // Reset Coroutine Dispatcher.
        Dispatchers.resetMain()
        context?.root
                ?.getStore(TEST_COROUTINE_DISPATCHER_NAMESPACE)
                ?.get(TEST_COROUTINE_DISPATCHER_KEY, TestCoroutineDispatcher::class.java)!!
                .cleanupTestCoroutines()

        // Clear LiveData Executor
        ArchTaskExecutor.getInstance().setDelegate(null)
    }

    override fun resolveParameter(parameterContext: ParameterContext?,
                                  extensionContext: ExtensionContext?) =
            if (parameterContext?.parameter?.type == TestCoroutineDispatcher::class.java)
                getTestCoroutineDispatcher(extensionContext).let { dipatcher ->
                    if (dipatcher == null) saveAndReturnTestCoroutineDispatcher(extensionContext)
                    else dipatcher
                }
            else getViewModel(extensionContext).let { viewModel ->
                if (viewModel == null) saveAndReturnContentViewModel(extensionContext)
                else viewModel
            }

    private fun getTestCoroutineDispatcher(context: ExtensionContext?) = context?.root
            ?.getStore(TEST_COROUTINE_DISPATCHER_NAMESPACE)
            ?.get(TEST_COROUTINE_DISPATCHER_KEY, TestCoroutineDispatcher::class.java)

    private fun saveAndReturnTestCoroutineDispatcher(extensionContext: ExtensionContext?) =
            TestCoroutineDispatcher().apply {
                extensionContext?.root
                        ?.getStore(TEST_COROUTINE_DISPATCHER_NAMESPACE)
                        ?.put(TEST_COROUTINE_DISPATCHER_KEY, this)
            }

    private fun getViewModel(context: ExtensionContext?) = context?.root
            ?.getStore(VIEWMODEL_NAMESPACE)
            ?.get(CONTENT_VIEWMODEL_KEY, ContentViewModel::class.java)

    private fun saveAndReturnContentViewModel(extensionContext: ExtensionContext?) =
            ContentViewModel().apply {
                extensionContext?.root
                        ?.getStore(VIEWMODEL_NAMESPACE)
                        ?.put(CONTENT_VIEWMODEL_KEY, ContentViewModel())
            }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...