JUnit 5 注释 - 不适用于 LiveData/参数化测试

JUnit 5 Annotations - Not Working with LiveData / Parameterized Tests

概览

预期行为

使用mockObject函数implementation with annotation syntax initialization for JUnit 5 as outlined in the documentation and Medium post by @oleksiyp替换模拟对象初始化。

当前行为

有问题的测试是 parameterized test as outlined by @phauer for JUnit 5 which seems to conflict with @ExtendWith(MockKExtension::class). In order to implement tests with LiveData the test must run synchronously in the local unit test using this InstantExecutorExtension designed by @JeroenMols

模拟对象初始化与 mockObject 函数一起按预期工作,但使用注释 @MockK.

失败

错误

警告message/Build失败:

Repeatable annotations with non-SOURCE retention are not yet supported.

实施

mockObject 函数实现(按预期工作)

@ExtendWith(InstantExecutorExtension::class)
class NavigateContentTests {
    private val mainThreadSurrogate = newSingleThreadContext("UI thread")
    private val contentViewModel = ContentViewModel()

    // This is the stream of tests to run in the Parameterized test below.
    private fun NavigateContent() = Stream.of(
            NavigateContentTest(
                    isRealtime = false,
                    feedType = MAIN,
                    timeframe = DAY,
                    mockFeedList = mockDbContentListForDay,
                    mockContent = mockArticleContent),
            ...)

    @BeforeAll
    fun beforeAll() { mockkObject(ContentRepository) }

    @AfterAll
    fun afterAll() { unmockkAll() // Re-assigns transformation of object to original state prior to mock. }

    @BeforeEach
    fun beforeEach() { Dispatchers.setMain(mainThreadSurrogate) }

    @AfterEach
    fun afterEach() {
        Dispatchers.resetMain() // Reset main dispatcher to the original Main dispatcher.
        mainThreadSurrogate.close()
    }

    @ParameterizedTest
    @MethodSource("NavigateContent")
    fun `Navigate Content`(test: NavigateContentTest) = runBlocking {
        every { ContentRepository.getMainFeedList(test.isRealtime, any()) } returns mockGetMainFeedList(
                test.mockFeedList, CONTENT)
        every {
            ContentRepository.queryLabeledContentList(test.feedType)
        } returns mockQueryMainContentList(test.mockFeedList)
        every { ContentRepository.getContent(test.mockContent.id) } returns mockGetContent(test)
        // Tests here...
        // Verification here...
    }
}

注解语法初始化(由于两个扩展@ExtendWith而无法正常工作)

@ExtendWith(InstantExecutorExtension::class)
@ExtendWith(MockKExtension::class)
class NavigateContentTests {

    // This object should be mocked.
    @MockK
    lateinit var contentRepository: ContentRepository

    private val mainThreadSurrogate = newSingleThreadContext("UI thread")
    private val contentViewModel = ContentViewModel()

    // This is the stream of tests to run in the Parameterized test below.
    private fun NavigateContent() = Stream.of(
            NavigateContentTest(
                    isRealtime = false,
                    feedType = MAIN,
                    timeframe = DAY,
                    mockFeedList = mockDbContentListForDay,
                    mockContent = mockArticleContent),
            ...)

    @BeforeAll
    fun beforeAll() {  MockKAnnotations.init(this, relaxUnitFun = true) // turn relaxUnitFun on for }

    @AfterAll
    fun afterAll() { unmockkAll() // Re-assigns transformation of object to original state prior to mock. }

    @BeforeEach
    fun beforeEach() { Dispatchers.setMain(mainThreadSurrogate) }

    @AfterEach
    fun afterEach() {
        Dispatchers.resetMain() // Reset main dispatcher to the original Main dispatcher.
        mainThreadSurrogate.close()
    }

    @ParameterizedTest
    @MethodSource("NavigateContent")
    fun `Navigate Content`(test: NavigateContentTest) = runBlocking {
        every { contentRepository.getMainFeedList(test.isRealtime, any()) } returns mockGetMainFeedList(
                test.mockFeedList, CONTENT)
        every {
            contentRepository.queryLabeledContentList(test.feedType)
        } returns mockQueryMainContentList(test.mockFeedList)
        every { contentRepository.getContent(test.mockContent.id) } returns mockGetContent(test)
        // Tests here...
        // Verification here...
    }
}

环境

根据此GitHub issue, as documented by the MockK creator, @oleksiy,这是一个错误。

一旦我看到错误已解决,我将更新此 post。