2016-07-12 8 views
0

Aus irgendeinem unerklärlichen Grund ein Feld (currentExp) ich im Konstruktor zuweisen ist nicht korrekt festgelegt, während ein Mock für meine Unittest verwendet. Ich gebe das Feld currentExp durch Laden über die loadExperience Methode unter Verwendung meiner Storage Klasse (die SharedPreferences verwendet). Wenn ich dies Unittesting, würde Ich mag die Storage Klasse verspotten, so kehrt loadexperience ein Wert von 10.Feldwert nicht festgelegt, wenn Mock und abstrakte Klasse verwendet

Hier ist meine konkrete Experience Klasse:

public class Experience extends StorageObject { 

    private int currentExp = 0; 

    public Experience() { 
     this(new Storage()); 
    } 

    @VisibleForTesting 
    protected Experience(Storage storage) { 
     super(storage); 
    } // Debug point #2 

    @Override 
    protected void init(Storage storage) { 
     this.currentExp = storage.loadExperience(); 
    } // Debug point #1 
} 

Es erstreckt sich StorageObject:

public abstract class StorageObject { 
    protected Storage storage; 

    protected StorageObject() { 
     this(new Storage()); 
    } 

    @VisibleForTesting 
    protected StorageObject(Storage storage) { 
     this.storage = storage; 
     init(storage); 
    } 

    protected abstract void init(Storage storage); 
} 

Und das ist mein Unittest:

@Test 
public void testConstructor_StorageValuePositive_IsSetAsCurrentExp() { 
    int expectedSavedExp = 10; 
    Storage storageMock = mock(Storage.class); 
    doReturn(expectedSavedExp).when(storageMock).loadExperience(); 

    Experience exp = new Experience(storageMock); 

    assertEquals(expectedSavedExp, exp.getCurrentExp()); 
} 

Während des Debuggens habe ich festgestellt, dass die Mock DOES funktioniert, und der Wert 10 ist currentExp am Debug-Punkt # 1 zugewiesen. Kurz danach, am Debug-Punkt # 2, scheint der Wert wieder 0 zu sein.

Wer hat eine Ahnung, was hier passiert und wie man dieses Problem löst?

Antwort

1

Das Problem hier ist die Reihenfolge der Initialisierung. Der Superkonstruktor passiert zuerst dann die Feldinitialisierung.

So Konstruktor setzt die currentExp darin 10 super Anruf ist dann wird das Feld initilized mit 0

Also, was können Sie tun? Einige Ideen: Verschieben Sie die currentExp in die Elternklasse oder geben Sie keinen Standardwert.

Mehr Lesestoff:

http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5

https://stackoverflow.com/a/14806340/5842844

+0

Großartig, danke! Ich denke du meinst 'currentExp' statt' expectedSavedExp'? ;-) Aber ich habe die Idee, wie man es löst, darauf kommt es an. ... Eine andere Idee: Weil ich 'Speicher' als ein Feld in 'StorageObject' eingestellt habe, könnte ich' currentExp' auch mit 'storage.loadExperience()' als Standardwert initialisieren, anstatt es im Konstruktor zuzuweisen . Auf diese Weise kann ich auch die Methode der "abstrakten Init" weglassen. Das scheint das unitest Problem zu lösen, aber ist es üblich/richtig das zu tun? –

+0

ups ja ich meinte currentExp. Sie könnten einfach die Init in die Kindklasse verschieben, es gibt keinen Grund dafür, dass sie auf der Elternklasse ist. – jbarat

Verwandte Themen