2016-07-12 16 views
0

對於某些無法解釋的原因,我在構造函數中指定的字段(currentExp)在我的unittest中使用模擬時未正確設置。我正在通過使用我的Storage類(使用SharedPreferences)通過loadExperience方法加載它來指定字段currentExp。當我在單元測試這一點,我想嘲笑Storage類,所以loadexperience返回的10使用模擬和抽象類時未設置字段值

值這裏是我的具體Experience類:

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 
} 

它擴展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); 
} 

這是我的單元測試:

@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()); 
} 

在調試過程中,我發現模擬DOES工作,並且在調試點#1處將10的值分配給currentExp。然後不久之後,在調試點#2,該值似乎再次爲0。

任何人都知道這裏發生了什麼,以及如何解決這個問題?

回答

1

這裏的問題是初始化順序。超級構造函數首先發生,然後是字段初始化。

所以你的構造函數在它currentExp對10位的超級電話則字段被以0

所以initilized你能做什麼?一些想法: 將currentExp移到父類或不要給它一個默認值。

更多閱讀材料:

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

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

+0

很好,謝謝! 我想你的意思是'currentExp'而不是'expectedSavedExp'? ;-) 但我知道如何解決這個問題,這纔是最重要的。 ... 另一個想法:因爲我在'StorageObject'中設置了'storage'作爲一個字段,所以我可以用'storage.loadExperience()'初始化'currentExp'作爲默認值,而不是在構造函數中賦值。這樣我也可以省略'abstract init'方法。 似乎解決了單元測試問題,但這樣做是否通用/正確? –

+0

ups是的,我的意思是currentExp。你可以將init移動到子類中,沒有理由將它放在父類上。 – jbarat

相關問題