使用模拟类和抽象类时未设置字段值



由于某种无法解释的原因,我在构造函数中分配的字段(currentExp)在为我的单元测试使用模拟时未正确设置。我通过使用我的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());
}

在调试时,我发现模拟确实有效,并且值 10 在调试点 #1 分配给currentExp。然后不久之后,在调试点 #2 处,该值似乎再次为 0。

任何人都知道这里发生了什么,以及如何解决这个问题?

这里的问题是初始化顺序。超级构造函数首先发生,然后进行字段初始化。

因此,您的构造函数将超级调用中的currentExp设置为 10,然后字段以 0 启动。

那你能做什么呢?一些想法:将currentExp移动到父类或不为其提供默认值。

更多阅读材料:

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

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

最新更新