6

JUnit テストのコンストラクターをprivate static final持つクラスにフィールドを設定しようとしています。privateコードを基本まで煮詰めると、次のようになります。

public class Foo {
    private static final boolean FLAG = false;
    private Foo() { /* don't call me */  }
    public static boolean get() { return FLAG; }
}

私のテストは次のようになります。

@RunWith(PowerMockRunner.class)
@PrepareEverythingForTest  // Whitebox fails without this line
public class FooTest {
    @Test
    public void testGet() {
        Whitebox.setInternalState(Foo.class, "FLAG", true);
        assertTrue(Foo.get());
    }
}

そして、これが私のPOMファイルからの抜粋です。

<junit.version>4.11</junit.version>
<powermock.version>1.5.4</powermock.version>
<mockito.version>1.9.5</mockito.version>

にブレークポイントを設定すると、IntelliJ のデバッガーでに設定されreturn FLAG;ていることがはっきりとわかります。それでも、テストは で失敗します。FLAGtrueAssertionError

これを機能させるために何をすべきか考えていますか?

更新:リフレクションの使用も機能しないようです:

@Test
public void testGet_usingReflection() throws Exception {
    setField(Whitebox.invokeConstructor(Foo.class), "FLAG", true);
    assertTrue(Foo.get());
}

public static void setField(Object targetObject, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
    Class clazz =  targetObject.getClass();
    Field field = clazz.getDeclaredField(fieldName);
    field.setAccessible(true);
    Field modifiers = Field.class.getDeclaredField("modifiers");
    modifiers.setAccessible(true);
    modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(targetObject, value);
}

このsetField()方法は、内部ライブラリから入手できるものです。残念ながら、同じ結果が得られます。AssertionError

更新 2: PowerMock を完全に削除してもあまり効果がないようです。

@Test
public void testGet_usingReflectionWithoutPowerMock() throws Exception {
    setField(Foo.class.getDeclaredField("FLAG"), true);
    assertTrue(Foo.get());
}

public static void setField(Field field, Object value) throws NoSuchFieldException, IllegalAccessException {
    field.setAccessible(true);
    Field modifiers = Field.class.getDeclaredField("modifiers");
    modifiers.setAccessible(true);
    modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(null, value);
}

このために、クラスレベルから PowerMock アノテーションを削除しました...

また、この質問をPowerMock メーリング リストにも投稿しました。

4

2 に答える 2

2

同様のテストを行いましたが、唯一の違いは、静的最終変数がObjectプリミティブ型ではないことでした。そして実際に変更booleanするBooleanと機能します。

public class Foo {
    private static final Boolean FLAG = false;
    private Foo() { /* don't call me */  }
    public static boolean get() { return FLAG; }
}

また、大きなプロジェクトの場合、すべてを準備するのに時間がかかる可能性があるためではなく、@PrepareForTest(SomeClass.class)where has static final フィールドを使用することをお勧めします。SomeClass@PrepareEverythingForTest

于 2015-11-03T20:52:13.513 に答える
0

WhiteBox.setInternalState は、final フィールドを持つクラスでは機能しません。

リフレクションを使用してこの問題を解決できます。

static void setFinalStatic(Field field, Object newValue) throws Exception {  
  field.setAccessible(true);  

  Field modifiersField = Field.class.getDeclaredField("modifiers");  
  modifiersField.setAccessible(true);  
  modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);  

  field.set(null, newValue);  
}  

ソース: https://code.google.com/p/powermock/issues/detail?id=324

于 2015-10-22T13:12:19.940 に答える