6

我对移动设备上的单元测试真的很陌生。我想为 Android 移动应用程序编写 JUnit 测试。我遇到了在 IDE 中测试的Robolectric(对我来说,Eclipse)

但我真的不明白 Robolectric 的影子对象。我应该将它们用作嘲弄吗?这些Shadow 对象如ShadowActivity 等的使用目的是什么?

例如,我在几乎每个 Activity 类的 onCreate 方法中都有 Crashlytics、Google Analytics 代码。当遇到这些行时,Robolectric 会抛出错误。ShadowActivity 能解决这些类型的问题吗?

很抱歉,但正如我所说,我在单元测试方面真的很新,Robolectric 文档对初学者没有帮助。

4

2 回答 2

13

但我真的不明白 Robolectric 的影子对象。我应该将它们用作嘲弄吗?这些Shadow 对象如ShadowActivity 等的使用目的是什么?

阴影有点像模拟或存根,但不完全相同。阴影的存在是为了添加额外的方法,这些方法可以在测试中用于检查底层 Android 对象的状态。例如,许多 Android 对象具有特定值的 setter,但没有 getter。我们可以将 getter 添加到阴影中,并在测试中使用它们来断言底层对象。

例如,我在几乎每个 Activity 类的 onCreate 方法中都有 Crashlytics、Google Analytics 代码。当遇到这些行时,Robolectric 会抛出错误。ShadowActivity 能解决这些类型的问题吗?

可能不是。为此,您应该使用依赖注入将 Crashlytics 或 GoogleAnalytics 的虚假版本注入到您的测试中。

Robolectric 的目的是伪造足够多的 Android 平台,以允许您在桌面 JVM 上运行测试 - 而不是模拟 Android。仍然可以使用良好的工程实践,例如依赖注入或模拟。

很抱歉,但正如我所说,我在单元测试方面真的很新,Robolectric 文档对初学者没有帮助。

我同意。我们正在努力让它变得更好,但我们还有很长的路要走。

于 2013-11-16T19:02:10.523 回答
0

关于:

例如,我在几乎每个 Activity 类的 onCreate 方法中都有 Crashlytics、Google Analytics 代码。当遇到这些行时,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");
    }
}
于 2015-07-03T21:28:58.473 回答