web-dev-qa-db-ja.com

Powermock2とKotlinを使用した静的クラスのモック

in Android私はPowermockのバージョン1.6.1を使用してきましたが、この実装はすべて静力学に非常に適しています。2.0.0-beta.5に変更したときは、まったく機能していません。実際、以前のからのアップグレードでも機能しませんでした。 == --- ==)1.6.1から1.7.1

私はこの実装を持っています:

// Power Mockito
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
testImplementation "org.powermock:powermock-module-junit4-rule-agent:2.0.0-beta.5"
testImplementation "org.powermock:powermock-module-junit4:2.0.0-beta.5"
//testImplementation 'org.powermock:powermock-module-junit4-rule:2.0.0-beta.5'

// Mockito
testImplementation "org.mockito:mockito-core:2.11.0"
testImplementation "com.nhaarman:mockito-kotlin-kt1.1:1.5.0"
androidTestImplementation("com.nhaarman:mockito-kotlin-kt1.1:1.5.0", {
    exclude group: 'org.mockito', module: 'mockito-core'
})
androidTestImplementation 'org.mockito:mockito-Android:2.11.0'

そして、私は1.6.1:で行っていたのと同じ方法でスタティックをモックしようとしています。

@RunWith(PowerMockRunner::class)
@PrepareForTest(SharedPreferencesHelper.Companion::class, ConfigUseCaseTests::class)
class ConfigUseCaseTests {

    lateinit var context: Context

    @Before
    fun setUp() {
        context = mock()
    }

    @Test
    fun getConfigs_fromJson() {
        PowerMockito.mockStatic(SharedPreferencesHelper.Companion::class.Java)

        val instance = mock<SharedPreferencesHelper.Companion>()
        doReturn("foo")
                .whenever(instance)
                .loadString(isA(), anyString(), anyString(), anyString())
//        whenever(instance.loadString(isA(), anyString(), anyString(), anyString())).thenReturn("foo") // This shows the same error
        PowerMockito.whenNew(SharedPreferencesHelper.Companion::class.Java)
                .withAnyArguments()
                .thenReturn(instance)

        val mockedFoo = instance.loadString(context, "", "", "") // This shows "foo"

        val mockedCompanion = SharedPreferencesHelper.loadString(context, "", "", "") // This is throwing NullPointerException

        Assert.assertEquals(mockedCompanion, "foo")
    }
}

私のSharedPreferencesHelperは次のようになります:

class SharedPreferencesHelper {
    companion object {

        @Suppress("NON_FINAL_MEMBER_IN_OBJECT")
        open fun loadString(context: Context, fileName: String, key: String, defaultValue: String?): String? {
            val sharedPreferences = getWithFileName(context, fileName)
            return if (!sharedPreferences.contains(key)) {
                defaultValue
            } else {
                sharedPreferences.getString(key, defaultValue)
            }
        }
    }
}

openで遊んでみましたが、うまくいきませんでした。

例外:(まったくわかりません)

Java.lang.NullPointerException
    at my.package.ConfigUseCaseTests.getConfigs_fromJson(ConfigUseCaseTests.kt:45)
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.lang.reflect.Method.invoke(Method.Java:498)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.Java:68)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.Java:326)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.Java:89)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.Java:97)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.Java:310)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.Java:131)

私は言うことができます、時々それはうまくいきます!!たまにしか起こらないのがすごいので、ビデオを追加します: https://youtu.be/YZObVLcERBo (途中と最後で見る)

11

コンパイル時にコンパニオンオブジェクトを作成する方法は、周囲のクラス内に静的フィールドを作成することです。静的スコープでインスタンス化されます(テストがインスタンス化される前)。

Javaで逆コンパイルすると次のようになります。

public final class SharedPreferencesHelper {
  public static final SharedPreferencesHelper.Companion Companion = new 
  SharedPreferencesHelper.Companion((DefaultConstructorMarker)null);
  // ...
}

これを機能させるには、Companionオブジェクトの作成をインターセプトする代わりに、指定されたフィールドにモックを割り当てる必要があります。これはPowerMockを使用する必要はなく、再帰を使用して実行できます: https://dzone.com/articles/how-to-change-private-static-final-fields ==

1
pablisco