gpt4 book ai didi

android - 如何使用 ParameterResolver 在 JUnit 5 中注入(inject)多个扩展值

转载 作者:行者123 更新时间:2023-11-29 02:18:15 35 4
gpt4 key购买 nike

如何使用 ParameterResolver 模式将多个值注入(inject)到测试中?

好像只能定义一个返回值。

目前,getStore 保存一个扩展值,该扩展值使用 ParameterResolver 作为参数注入(inject)。在此示例中,它是一个注入(inject)的 TestCoroutineDispatcher,用于管理本地 JUnit 测试中的协程生命周期。 如果需要从同一个扩展中注入(inject)第二个值怎么办?

实现

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

最佳答案

感谢您的洞察力@Slaw !

Well, both #supportsParameter and #resolveParameter is invoked for each parameter in the method. So you currently have a test to see if the parameter type is TestCoroutineDispatcher which means you can add a test for the shared ViewModel type. Then resolve the correct parameter based on the type. If you want to share the ViewModel across multiple tests then you can store a reference to it in the parent/root 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())
}
}

关于android - 如何使用 ParameterResolver 在 JUnit 5 中注入(inject)多个扩展值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58683695/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com