Пользовательское правило JUnit позволяет пройти все тесты независимо от того, что - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть файл, который ссылается на некоторые статические методы:

class MyViewModel {

    fun test() { }

    companion object {
        private val MY_STRING = ResourceGrabber.grabString(R.string.blah_blah)
    }
}

В моем тесте JUnit для этого файла я пишу некоторый код, чтобы смоделировать мой захватчик ресурсов при настройке. Он компилируется и запускается, и следующий тест не проходит, как я ожидал:

@PrepareForTest(ResourceGrabber::class)
@RunWith(PowerMockRunner::class)
class MyViewModelTest {
    private lateinit var viewModel: MyViewModel

    @Before
    fun setup() {
        PowerMockito.mockStatic(ResourceGrabber::class.java)
        val mockResourceGrabber = Mockito.mock(ResourceGrabber::class.java)

        whenever(mockResourceGrabber.grabString(Mockito.anyInt())).thenAnswer { invocation ->
            val res: Int? = invocation?.arguments?.get(0) as? Int
            TestResourceGrabber.grabString(res)
        }

        viewModel = MyViewModel()
    }

    @Test
    fun someTest() {
        // Fails, as expected.
        assertEquals(2, 3)
    }
}

Здесь вещи становятся странными. Недавно я узнал о пользовательских правилах JUnit, которые вы можете использовать, чтобы избежать дублирования кода между тестами. В этом случае мне не нужно копировать и вставлять мою работу по захвату ресурсов в каждый отдельный набор тестов, в котором она используется, поэтому я создал собственное правило:

class ResourceGrabberRule : TestRule {
    override fun apply(base: Statement?, description: Description?): Statement {
        return object : Statement() {
            override fun evaluate() {
                PowerMockito.mockStatic(ResourceGrabber::class.java)
                val mockResourceGrabber = Mockito.mock(ResourceGrabber::class.java)

                whenever(mockResourceGrabber.grabString(Mockito.anyInt())).thenAnswer { invocation ->
                    val res: Int? = invocation?.arguments?.get(0) as? Int
                    TestResourceGrabber.grabString(res)
                }
            }
        }
    }
}

Ниже приведена реализация этого. Сумасшедшая вещь в том, что теперь КАЖДЫЙ тест проходит независимо от того, что:

@PrepareForTest(ResourceGrabber::class)
@RunWith(PowerMockRunner::class)
class MyViewModelTest {
    private lateinit var viewModel: MyViewModel

    @Rule
    @JvmField
    val resourceGrabber = ResourceGrabberRule()

    @Before
    fun setup() {
        viewModel = MyViewModel()
    }

    @Test
    fun someTest() {
        // PASSES!!!?!?!?!?!
        assertEquals(2, 3)
    }
}

Я не уверен, в чем проблема. Я пробовал создавать и запускать тесты как из Android Studio, так и из командной строки. Я не знаю, правильно ли я реализовал свое правило, или это проблема с правилом JUnit, связанным с Powermock, или это проблема с обработкой аннотаций Kotlin. Тесты компилируются и запускаются, но просто проходят независимо от того, что находится внутри самих тестов.

Я открыт для комментариев об архитектуре здесь (я уверен, что у сообщества есть много), но я действительно ищу объяснение того, почему написанное мной правило проходит каждый тест.

1 Ответ

0 голосов
/ 12 сентября 2018

В вашем пользовательском TestRule вам нужно позвонить base.evaluate(), чтобы продолжить цепочку правил https://github.com/junit-team/junit4/wiki/rules#custom-rules

...