gpt4 book ai didi

Android Activity 单元测试中模拟数据源的技巧

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:52:43 28 4
gpt4 key购买 nike

我是单元测试的新手,我一直在学习如何使用 Android 的 jUnit 框架(使用 ActivityInstrumentationTestCase2),但我无法弄清楚如何注入(inject)模拟数据源和 Activity ,示例:

在 Activity 中我有这个

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 传递到连接到 Web 服务的适配器中,以便为适配器引入产品。在我的测试中,我不想连接到网络服务。将模拟数据源注入(inject) Activity 以进行测试的最佳技术是什么?我应该在 Application 实例中创建 ProductDataSource,然后在我的测试中使用 MockApplication 来创建模拟数据源吗?

谢谢

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

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
); //

最佳答案

从您的分辨率来看,您更多地将“模拟”称为 stub 一些测试数据。当您更关心功能而不真正关心细节时,这始终是推进开发的好方法。

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

模拟通过为接口(interface)创建模拟“具体”对象来工作。请记住,接口(interface)只是一个约定,表明您的类将提供指定的方法。

假设您有一个像这样的 ProductsDatasource 接口(interface)实现:

public interface IProductsDatasource {

public List<Product> getProducts();

}

和具体类型:

public class ProductsDatasource implements IProductsDatasource {

private List<Product> mProducts;

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

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

}

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

public class TargetAdapter {

private IProductsDatasource mDatasource;

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

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

}

所以这是一个没有模拟的测试用例,它详细说明了我在说什么。

@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);
}

因此,为了测试我的适配器,我必须创建一个新的适配器和一个新的数据源。我并不真正关心数据源,我只需要确保我的适配器执行我希望它执行的操作。 Mocking 允许我通过指定接口(interface)类型和配置我希望它的行为方式来单独测试我的适配器。现在我不再局限于具体的类实现来测试我的适配器。

下面是一个示例,我使用 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);

}

既然您说您是单元测试的新手,我想指出 Mock 对象在单元测试中的强大功能以及您如何利用它们来编写更好的代码。您还可以设置模拟对象以确保目标对象调用模拟对象的方法。我经常在不关心方法的实现或结果的地方使用它,我只是想确保我的类在应该调用它的时候调用它。现在要完成所有这些工作,您必须使用接口(interface),但只需执行重构 -> 提取接口(interface)

就非常容易了

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

关于Android Activity 单元测试中模拟数据源的技巧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3663164/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com