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

时间:2016-07-12 22:27:23

标签: android unit-testing constructor mocking abstract-class

由于某些无法解释的原因,我在构造函数中分配的字段(currentExp)在使用模拟器进行单元测试时未正确设置。我是通过使用我的currentExp类(使用SharedPreferences)通过loadExperience方法加载字段Storage来分配字段的。当我对此进行单元测试时,我想模拟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 个答案:

答案 0 :(得分:1)

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

因此,你的构造函数将require(BASE."template/head.php"); 中的currentExp设置为超级调用,然后该字段将被启动为0。

那你能做什么?一些想法: 将currentExp移至父类,或者不要为其提供默认值。

更多阅读材料:

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

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