如何让我的活动使用测试数据?

时间:2017-04-14 15:20:18

标签: android testing mockito android-espresso

我有一个应用程序,它显示来自Web API的数据(帖子)。

  • 后台服务会在某个未知时间同步此数据并保存。
  • 访问我的主要活动时,它会加载此数据并将其显示在RecyclerView
  • 通过单件类
  • 处理加载

我目前正在测试主要活动如下

@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);

@Test
public void testDataLoad() {
    int postsTotal = DataSingleton.getInstance().getPostsCount();
    ViewInteraction empty = onView(withId(R.id.empty_view));
    ViewInteraction recycler = onView(withId(R.id.recycler_view));
    if (postsTotal == 0) {
        empty.check(matches(isDisplayed()));
        recycler.check(matches(not(isDisplayed())));
    } else {
        empty.check(matches(not(isDisplayed())));
        recycler.check(matches(isDisplayed()));
        recycler.check(new RecyclerViewItemCountAssertion(greaterThan(postsTotal)));
    }
}

我知道这不是编写测试的正确方法。我希望能够使用空数据集和非空集测试两者,以便if-else是两个单独的测试。我认为我能实现的唯一方法是模拟数据。

还有其他方法吗? 我可以使用Mockito使MainActivity使用模拟数据而无需修改生产代码吗?是我唯一的选择,让它注入真实或模拟的数据提供者来代替我的单身人士吗?

每次只卸载并重新安装我的应用程序是否更好,因此没有数据可以开始,然后继续进行实际数据测试?

1 个答案:

答案 0 :(得分:0)

Android Activity很重,很难测试。因为我们无法控制构造函数,所以很难交换测试双精度。

要做的第一件事是确保依赖于数据源的抽象而不是结果。因此,如果您使用带有getPostsCount()方法的单例,则提取接口:

interface DataSourceAbstraction {
    int getPostsCount();
}

创建一个实现接口的包装类:

class ConcreteDataSource implements DataSourceAbstraction {
    @Override
    int getPostsCount() {
        return DataSingleton.getInstance().getPostsCount();
    }
}

并使活动依赖于而不是具体的DataSingleton

DataSourceAbstraction dataSourceAbstraction;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super(savedInstanceState);
    injectMembers();
}

@VisibleForTesting
void injectMembers() {
    dataSourceAbstraction = new ConcreteDataSource();
}

现在,您可以通过子类化和覆盖具有宽松可见性的injectMembers来交换测试双精度。在企业开发中这样做是个坏主意,但是在Android活动中没有控制类的构造函数的选项较少。

您现在可以写:

DataSourceAbstraction dataSource;

//system under test
MainActivity mainActivity

@Before
public void setUp() {
    mockDataSource = Mockito.mock(DataSourceAbstraction.class);
    mainActivity = new MainActivity() {
        @Override
        void injectMembers() {
            dataSourceAbstraction = mockDataSource;
        }
    };
}