首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >活动单元测试中模拟数据源的Android技术

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

Stack Overflow用户
提问于 2010-09-07 22:14:21
回答 1查看 5.1K关注 0票数 6

我刚刚开始进行单元测试,我一直在学习如何为android使用jUnit框架(使用ActivityInstrumentationTestCase2),但我很难找到如何将模拟数据源注入和活动的方法,例如:

在活动中我有这个

代码语言:javascript
复制
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);

}

目前,我将一个ProductDataSource传递到适配器中,该适配器连接到一个webservice,以便为适配器引入产品。在我的测试中,我不想连接到webservice。在测试活动中注入模拟数据源的最佳技术是什么?我应该在应用程序实例中创建ProductDataSource,然后在测试中使用MockApplication来创建模拟数据源吗?

谢谢

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

代码语言:javascript
复制
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
); // 
EN

回答 1

Stack Overflow用户

发布于 2012-06-14 17:56:46

从您的解决方案来看,您更多地将“嘲弄”称为顽固不化一些测试数据。当您更关心功能而不真正关心细节时,这始终是更好地推进开发的好方法。

所以我只是给你这个答案,因为你说你是新的单元测试。因此,如果您正在编写依赖于ProductsDatasource的单元测试,您还可以使用一个模拟框架插入一个“模拟”对象,而不是阻塞一个具体的类。我更多地使用.Net,而不是Java,但我的所有代码示例都将使用JUnit和JMock来描述我正在讨论的内容。

模拟的工作方式是为接口创建模拟“具体”对象。记住,接口只是一个契约,它说您的类将提供指定的方法。

因此,假设您有一个类似于的ProductsDatasource接口实现:

代码语言:javascript
复制
public interface IProductsDatasource {

    public List<Product> getProducts();

}

和一种具体类型:

代码语言:javascript
复制
public class ProductsDatasource implements IProductsDatasource {

    private List<Product> mProducts;

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

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

}

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

代码语言:javascript
复制
public class TargetAdapter {

    private IProductsDatasource mDatasource;

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

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

}

因此,这里有一个测试用例,没有嘲弄,这详细说明了我所说的.

代码语言:javascript
复制
@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);
}

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

下面是一个示例,其中我使用JMock创建一个模拟数据源:

代码语言:javascript
复制
@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);

}

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

在发布之前,我在eclipse中运行了所有这些代码,所以如果您想要使用它,代码就可以工作。希望这能有所帮助!

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3663164

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档