用于活动单元测试中的模拟数据源的Android技术

lon*_*dsi 6 android listview unit-testing adapter

我是单元测试的新手,我一直在学习如何使用jUnit框架用于android(使用ActivityInstrumentationTestCase2),但我在如何将模拟数据源注入和活动时遇到了麻烦,例如:

在活动中我有这个

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState,R.layout.market_screen);
        ListView products = (ListView)findViewById(R.id.product_list);
        MarketsAdapter adapter = new  MarketsAdapter(this, new ProductDataSource());
        products.setAdapter(adapter);

}
Run Code Online (Sandbox Code Playgroud)

我目前将ProductDataSource传递给适配器,该适配器连接到web服务以引入适配器的产品.在我的测试中,我不想连接到webservice.将模拟数据源注入活动进行测试的最佳技术是什么?我应该在Application实例中创建ProductDataSource,然后在我的测试中使用MockApplication来创建模拟数据源吗?

谢谢

我通过在测试类setUp()方法中执行以下操作来解决:获取对它的引用ListView并使用设置模拟数据源setAdapter(MockDataSource).这必须在UI线程上使用runOnUiThread()方法运行.

mActivity = getActivity();
mDataSource = new FakeDataSource();     
mMarketsListView = (ListView)mActivity.findViewById(R.id.product_list);
mActivity.runOnUiThread(
      new Runnable() {
        public void run() {
          mMarketsListView.setAdapter(new MarketsAdapter(mActivity,mDataSource));

        } // end of run() method definition
   } // end of anonymous Runnable object instantiation
); // 
Run Code Online (Sandbox Code Playgroud)

jer*_*rts 7

根据你的决议判断,你更多地将"模拟"称为剔除一些测试数据.当您更关注功能并且不关心细节时,这总是一种更好的开发方式.

所以我只是向你提供这个答案,因为你说你不熟悉单元测试.因此,如果您正在编写依赖于ProductsDatasource的单元测试,您还可以使用Mocking框架插入"模拟"对象,而不是删除具体类.我使用.Net而不是Java工作,但我的所有代码示例都将使用JUnit和JMock来描述我正在谈论的内容.

模拟通过为接口创建模拟"具体"对象来工作.请记住,接口只是一个合同,表明您的类将提供指定的方法.

所以说你有一个这样的ProductsDatasource接口实现:

public interface IProductsDatasource {

    public List<Product> getProducts();

}
Run Code Online (Sandbox Code Playgroud)

具体类型:

public class ProductsDatasource implements IProductsDatasource {

    private List<Product> mProducts;

    public ProductsDatasource(List<Product> products) {
        mProducts = products;
    }

    public List<Product> getProducts() {
        return mProducts;
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,假设您正在进行单元测试,比如TargetAdapter,它接收一个ProductsDatasource.如果您创建一个新的ProductsDatasource,那么您将具有依赖关系.您的单元测试现在取决于您正在测试的类和ProductsDatasource.也许你已经在另一个套件中测试了ProductsDatasource.

public class TargetAdapter {

    private IProductsDatasource mDatasource;

    public TargetAdapter(IProductsDatasource datasource) {
        mDatasource = datasource;
    }

    public List<Product> products() {
        return mDatasource.getProducts();
    }

}
Run Code Online (Sandbox Code Playgroud)

所以这是一个测试用例,没有嘲笑,详细说明了我在说什么.

@Test
public void TargetAdapterReturnsProducts() {

    List<Product> data = new ArrayList<Product>();
    data.add(new Product("Sample Product 1"));
    data.add(new Product("Sample Product 2"));
    data.add(new Product("Sample Product 3"));


    TargetAdapter adapter = new TargetAdapter(new ProductsDatasource(data)); // See the dependency
    List<Product> products = adapter.products();

    Assert.assertNotNull(adapter);
    Assert.assertTrue(products.size() == 3);
}
Run Code Online (Sandbox Code Playgroud)

因此,要测试我的适配器,我必须创建一个新的适配器和一个新的数据源.我并不真正关心数据源,我只需要确保我的适配器完成了我打算做的事情.Mocking允许我通过指定接口类型并配置我希望它的行为方式来单独测试我的适配器.现在我没有被绑定到具体的类实现来测试我的适配器.

所以这是一个例子,我使用JMock创建一个模拟数据源:

@Test
public void MockingTest() {

    final Mockery context = new Mockery();

    final List<Product> mockData = new ArrayList<Product>();
    mockData.add(new Product("Sample Product 1"));
    mockData.add(new Product("Sample Product 2"));
    mockData.add(new Product("Sample Product 3"));

    final IProductsDatasource mockDatasource = context.mock(IProductsDatasource.class);

    context.checking(new Expectations(){{
        oneOf (mockDatasource).getProducts(); will(returnValue(mockData));  // This is where I tell JMock to return my test data when getProducts() is called
    }});

    TargetAdapter adapter = new TargetAdapter(mockDatasource); // No dependency ;)
    List<Product> products = adapter.products();

    Assert.assertNotNull(adapter);
    Assert.assertTrue(products.size() == 3);

}
Run Code Online (Sandbox Code Playgroud)

既然你说你是单元测试的新手,我想在单元测试中指出Mock对象的强大功能,以及如何利用它们来编写更好的代码.您还可以设置模拟对象以确保目标对象在模拟上调用方法.我使用了很多,我不关心方法或结果的实现,我只是想确保我的类在它应该的时候调用它.现在要使所有这些工作,你必须使用接口,但只是做一个重构 - >提取接口很容易

我在发布它之前在eclipse中运行了所有这些,所以如果你想玩它,代码就可以了.希望这可以帮助!