2016-04-23 2 views
1

Ich versuche, die folgende Klasse zu testen, die zu einem Singleton aufruft, der eine private statische Endvariable initialisiert, indem es es mockt, folgend this Beispiel.Was mache ich falsch falsch diese private statische letzte Variable mit Mockito und Reflexion?

Hier ist, was ich tue

public class ClassToTest { 

private static final boolean CONF_FLAG = Configuration.getConfig() 
.get(Status.Initialization).getConfFlag(); // throws an NPE 

public methodToTest(TestObject a){ 
... 
} 
} 

wo Stand ein Enum ist.

Prüfklasse:

public class TestClassToTest{ 

TestObject a; 
ClassToTest t; 
    @Before 
public void setUp() throws Exception { 
    setFinalStatic(ClassToTest.class.getDeclaredField("CONF_FLAG"), true);// this fails! 
    a = mock(TestObject.class); 
    t = new ClassToTest(); 
} 
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); 
} 

}

Ich interessiere mich nicht für den Wert von CONF_FLAG aber kann nicht scheinen, um es zu verspotten. Was mache ich falsch?

Antwort

1

Wenn Ihre Klasse geladen wird, dann wird diese Zeile

genannt
private static final boolean CONF_FLAG = Configuration.getConfig().get(Status.Initialization).getConfFlag(); 

Also, um das Problem zu beheben Ich mag würde PowerMock Verwendung vorzuschlagen.

Mit PowerMock können Sie einfach unnecessary behavior überspringen, indem Sie @SuppressStaticInitilizationFor verwenden.

Außerdem werden Sie in der Lage sein, leicht gesetzt internen Zustand:

Whitebox.setInternalState(ClassToTest.class, "CONF_FLAG", true) 

Natürlich wird es für den Fall, wenn Sie eine neue Bibliothek hinzufügen können.

1

Ihr Code in TestClassToTest sieht gut aus, aber ClassToTest.class.getDeclaredField("CONF_FLAG") Zugriff auf den statischen endgültigen ClassToTest#CONF_FLAG Feld initialisieren, die Sie führt zu einem NullPointerException anzuzeigen. Ich nehme an, dass Sie den Quellcode in ClassToTest nicht ändern können. Gibt es zur Behebung des Problems noch weitere Schritte, die Sie in setUp() durchführen können, um den Singleton Configuration zu initialisieren, zum Beispiel mit seinen öffentlichen API-Methoden, so dass der Aufruf Configuration.getConfig().get(Status.Initialization).getConfFlag() erfolgreich ist?

Wenn dies der Fall ist, können Sie diesen Ansatz der Vorbereitung des Configuration Objekts für Ihre Tests verwenden, anstatt Reflektionen zu verwenden.

+0

+1. Um hier hinzuzufügen, solange der Aufruf als Teil der statischen Feldinitialisierung erfolgt, haben Sie wenig Kontrolle über den Zeitpunkt des Aufrufs und haben praktisch keine Gelegenheit, ihn für Tests zu ersetzen. Als Faustregel gilt: Wenn ein Aufruf gefährlich genug ist, um möglicherweise eine Ausnahme auszulösen oder in Tests zu spotten, möchten Sie das nicht in einem statischen Initialisierer. –

+0

@Jeff Bowman, @ ck1 Ja, ich verstehe den Teil, der es nicht in den statischen Initialisierer legt, aber das ist ein Stück Legacy-Code, mit dem ich geschlagen wurde und ich versuche irgendwie, mich damit herumzuarbeiten 'getConfig()' ist eine statische Methode. Gibt es irgendeine Möglichkeit, den gesamten Aufruf an den Singleton zu übertragen? Wenn ja, würde ich Code/Pseudocode sehr schätzen. – MuleNoob