【问题标题】:Robolectric's Shadow Object and MockingRobolectric 的阴影对象和模拟
【发布时间】:2013-11-15 09:36:20
【问题描述】:
我对移动设备上的单元测试非常陌生。我想为 Android 移动应用程序编写 JUnit 测试。我遇到了Robolectric,它正在 IDE 中进行测试(对我来说,Eclipse)
但我真的不明白 Robolectric 的影子对象。我应该将它们用作嘲弄吗?
ShadowActivity等这些Shadow对象的使用目的是什么?
例如,我在几乎每个 Activity 类的 onCreate 方法中都有 Crashlytics、Google Analytics 代码。当遇到这些行时,Robolectric 会抛出错误。 ShadowActivity 能解决这些类型的问题吗?
很抱歉,但正如我所说,我是单元测试的新手,Robolectric 文档对初学者没有帮助。
【问题讨论】:
标签:
java
android
unit-testing
junit
robolectric
【解决方案1】:
但我真的不明白 Robolectric 的影子对象。我是不是该
拿它们当嘲讽?这些Shadow对象的使用目的是什么
像 ShadowActivity 等?
阴影有点像模拟或存根,但并不完全相同。阴影的存在是为了添加额外的方法,这些方法可以在测试中用于检查底层 Android 对象的状态。例如,许多 Android 对象具有特定值的 setter,但没有 getter。我们可以将 getter 添加到阴影中,并在测试中使用它们来断言底层对象。
例如,我在 onCreate 中有 Crashlytics、Google Analytics 代码
几乎每个 Activity 类中的方法。 Robolectric 抛出错误时
它遇到了这些行。 ShadowActivity 能解决这些问题吗
问题类型?
可能不会。为此,您应该使用依赖注入将 Crashlytics 或 GoogleAnalytics 的虚假版本注入您的测试。
Robolectric 的目的是伪造足够多的 Android 平台,让您能够
在您的桌面 JVM 上运行测试 - 而不是模拟 Android。仍然可以使用良好的工程实践,例如依赖注入或模拟。
很抱歉,正如我所说,我是单元测试的新手
Robolectric 文档对初学者没有帮助。
我同意。我们正在努力让它变得更好,但我们还有很长的路要走。
【解决方案2】:
关于:
例如,我在 onCreate 中有 Crashlytics、Google Analytics 代码
几乎每个 Activity 类中的方法。 Robolectric 抛出错误时
它遇到了这些行。 ShadowActivity 能解决这些问题吗
问题类型?
您可以将对库的调用封装在实现某种 AnalyticsFacade 的 Facade 实现中,并创建一个封装所有实现的类,并将常见行为委托给它们。
public interface Analytics{
void sendEvent(String category, String action, Map<String,String> params);
void log(String msg);
}
public class AnalyticsFacade implements Analytics{
private List<Analytics> analyticsServices;
public AnalyticsFacade()
{
this.analyticsServices = new ArrayList<Analytics>();
}
public void addAnalyticsService(Analytics analytics){
analyticsServices.add(analytics);
}
@Override
public void sendEvent(String category, String action, Map<String, String> params)
{
for(Analytics service: analyticsServices){
service.sendEvent(category,action,params);
}
}
@Override
public void log(String msg)
{
for(Analytics service: analyticsServices){
service.log(msg);
}
}
}
public class GoogleAnalytics implements Analytics{
private Tracker tracker;
public GoogleAnalytics(Tracker tracker)
{
this.tracker = tracker;
}
@Override
public void sendEvent(String category, String action, Map<String, String> params)
{
//Note that this method signature has changed since GA v2 , now you pass a Map and
//it has a builder in order to create it
tracker.send(category,action,params);
}
@Override
public void log(String msg)
{
throw new RuntimeException("Not implemented");
}
}