Extending Robolectric

Robolectric is a work in progress, and we welcome contributions from the community. We encourage developers to use the standard GitHub workflow to fork, enhance, and submit pull requests to us.

Shadow Classes

Robolectric defines many shadow classes, which modify or extend the behavior of classes in the Android OS. When an Android class is instantiated, Robolectric looks for a corresponding shadow class, and if it finds one it creates a shadow object to associate with it. Every time a method is invoked on an Android class, Robolectric ensures that the shadow class‘ corresponding method is invoked first (if there is one), so it has a chance to work its magic. This applies to all methods, even static and final methods, because Robolectric is extra tricky!

//robolectric定义了很多影子类,这些类修改或者继承了Android操作系统中类的行为,当一个android类被初始化了,robolectric寻找一个对应的影子类,而且如果它找到了他就会创建一个与它关联的影子对象。每次一个方法被Android类调用,rebolectric都会确保影子类对应的方法会首先被调用(如果有这个对应的方法),影子应用到了所有的方法,深知静态和final方法。因为robolectrix很牛逼。

What‘s in a Name?

Why "Shadow?" Shadow objects are not quite Proxies, not quite Fakes, not quite Mocks or Stubs. Shadows are sometimes hidden, sometimes seen, and can lead you to the real object. At least we didn‘t call them "sheep", which we were considering.

//反正就是和之前的原生的功能不是很一样。这个名字已经很不错了,和我们之前考虑过的“胆小鬼”相比。

Adding Functionality

If the shadow classes provided with Robolectric don‘t do what you want, it‘s possible to change their behavior for a single test, a group of tests, or for your whole suite. Simply declare a class (let‘s say ShadowFoo) and annotate it @Implements(Foo.class). Your shadow class may extend one of the stock Robolectric shadows if you like. To let Robolectric know about your shadow, annotate your test method or class with the @Config(shadows=ShadowFoo.class), or create a file calledorg.robolectric.Config.properties containing the line shadows=my.package.ShadowFoo.

//如果影子类提供的没有你想要的,对于某一个测试,或者一些测试,或者全部的测试类做一些修改是必要的。只需要声明一个类然后注释它@Implements。为了让robolectric知道你的影子,使用 @Config(shadows=ShadowFoo.class)注释你的测试方法或者类

From Robolectric 2.0 on, the number of shadow classes needed is greatly reduced, because real Android OS code is present. Methods on your shadow class are able to call through to the Android OS code if you like, using Robolectric.directlyOn().

Shadow Classes

Shadow classes always need a public no-arg constructor so that the Robolectric framework can instantiate them. They are associated to the class that they Shadow with an @Implements annotation on the class declaration. In general, they should be implemented as if from scratch, the facilities of the classes they Shadow have almost always been removed and their data members are difficult to access. The methods on a Shadow class usually either Shadow the methods on the original class or facilitate testing by setting up return values or providing access to internal state or logged method calls.

//shadow类总是需要一个公有的午餐构造方法以便让robo框架可以初始化。他们会和使用 @Implements 声明的类关联起来作为它们的影子。影子类中的方法要么是对原来类中方法的重复,要么修改了返回值或者提供的全局变量的访问或者记录方法调用轨迹。

Shadow classes should mimic the production classes‘ inheritance hierarchy. For example, if you are implementing a Shadow forViewGroupShadowViewGroup, then your Shadow class should extend ViewGroup‘s superclass‘s Shadow, ShadowView.

//影子类应该同样照搬原类的继承关系。

  ...
  @Implements(ViewGroup.class)
  public class ShadowViewGroup extends ShadowView {
  ...

Methods

Shadow objects implement methods that have the same signature as the Android class. Robolectric will invoke the method on a Shadow object when a method with the same signature on the Android object is invoked.

Suppose an application defined the following line of code:java ... this.imageView.setImageResource(R.drawable.pivotallabs_logo); ...

Under test the ShadowImageView#setImageResource(int resId) method on the Shadow instance would be invoked.

//假设应用中定义了一行代码 this.imageView.setImageResource(R.drawable.pivotallabs_logo);,那在测试下影子类的实例的对应影子方法也会被调用

Shadow methods must be marked with the @Implementation annotation. Robolectric includes a lint test to help ensure this is done correctly.

//影子方法必须使用 @Implementation注释标记。

@Implements(ImageView.class)
public class ShadowImageView extends ShadowView {
  ...
  @Implementation
  public void setImageResource(int resId) {
    // implementation here.
  }
}

It is important Shadow methods are implemented on the corresponding Shadow of the class in which they were originally defined. Otherwise Robolectric‘s lookup mechanism will not find them (even if they have been declared on a Shadow subclass.) For example, the method setEnabled() is defined on View. If a setEnabled() method is defined on ShadowViewGroup instead of ShadowViewthen it will not be found at run time even when setEnabled() is called on an instance of ViewGroup.

//shadow方法只会实现对应原类的方法,子类的实现在这个逻辑里无效不可继承

Shadowing Constructors

Once a Shadow object is instantiated, Robolectric will look for a method named __constructor__ which has the same arguments as the constructor that was invoked on the real object.

//一旦shadow对象被初始化,robo将会寻找和真实对象中被调用的参数一样的,名字为 __constructor__的方法调用。

For instance, if the application code were to invoke the TextView constructor which receives a Context:

new TextView(context);

Robolectric would invoke the following __constructor__ method that receives a Context:

@Implements(TextView.class)
public class ShadowTextView {
  ...
  public void __constructor__(Context context) {
    this.context = context;
  }
  ...

Getting access to the real instance

Sometimes Shadow classes may want to refer to the object they are shadowing, e.g. to manipulate fields. A Shadow class can accomplish this by declaring a field annotated @RealObject:

//有时候shadow类可能想要引用他们shadow的对象,例如,去操作变量。一个shadow类可以通过声明@RealObject注解的对象来实现

@Implements(Point.class)
public class ShadowPoint {
  @RealObject private Point realPoint;
  ...
  public void __constructor__(int x, int y) {
    realPoint.x = x;
    realPoint.y = y;
  }
}

Robolectric will set realPoint to the actual instance of Point before invoking any other methods.

It is important to note that methods called on the real object will still be intercepted and redirected by Robolectric. This does not often matter in test code, but it has important implications for Shadow class implementors. Since the Shadow class inheritance hierarchy does not always mirror that of their associated Android classes, it is sometimes necessary to make calls through these real objects so that the Robolectric runtime will have the opportunity to route them to the correct Shadow class based on the actual class of the object. Otherwise methods on Shadows of base classes would be unable to access methods on the Shadows of their subclasses.

时间: 2024-08-02 02:50:40

Extending Robolectric的相关文章

(转) Written Memories: Understanding, Deriving and Extending the LSTM

R2RT Written Memories: Understanding, Deriving and Extending the LSTM Tue 26 July 2016 When I was first introduced to Long Short-Term Memory networks (LSTMs), it was hard to look past their complexity. I didn’t understand why they were designed they

Robolectric 单元测试中使用 Ressource

单元测试类中: @RunWith(RobolectricGradleTestRunner.class) @Config(constants=BuildConfig.class, sdk = 21) 获取 context: RuntimeEnvironment.application build.gradle 中: 若使用 multidextestCompile 'org.robolectric:shadows-multidex:3.0' 否则testCompile 'org.robolectri

Extending Markov to Hidden Markov

Extending Markov to Hidden Markov a tutorial on hidden markov models, Hidden Markov Models, hidden markov models tutorial, markov chains, markov chains examples,markov chains tutorial, markov models When we talked about Markov Process and training th

Extending JavaScript Natives

Most built-in JavaScript types are constructors whose prototypes contain the methods and other properties that define their default behavior: //(results will vary by browser) Object.getOwnPropertyNames(Function.prototype) //["bind", "argume

[译] Extending jQuery Part1 Simple extensions

本章包含: JQuery 的起源和目标. 你能扩展JQuery 的那些部分. JQuery 扩展的实例. 如今,JQuery 已经是网络上最受欢迎的JavaScript Library. 1.1 jQuery 背景 JQuery 的主要特性如下: 元素选择器 元素遍历 元素操作 事件处理 特效以及动画 Ajax 扩展性 各种各样的帮助函数 跨浏览器 1.1.1 起源 起源其实不是那么重要,本来作者取名叫做jSelect, 悲剧的是该名字已经被占用,所以便改叫jQuery. 1.1.2 成长历程

[AngularJS] angular-formly: Extending Types

Extending types is one of the ways that makes angular-formly help you keep your Angular forms DRY. When use responsibly, they can make it much easier to manage common types, allowing you to add a bit of functionality to a common type. (function() { '

Android Bound Service(一) ----- Extending Binder Service(进程内绑定Service的简单例子)

ref:http://developer.android.com/guide/components/bound-services.html? 前言 重新学习这一项技术,主要的原因,是因为以前没有好好的学,那时总觉得作品能动,能完成工作就好了,而这种得过且过的想法,大大地影响了我的技术程度,也因此,在这个这个博客里,有许多的复习心得.有幸得到一位前辈的指导,指出,若只是学习,而无实际应用,这样进步会较少,因此,最好要多看源码,并且自己多尝试多实践,这样学习一万小时,应该能有小进步,因此开始了 Bo

Robolectric使用教程

转载请标明出处:http://blog.csdn.net/shensky711/article/details/53561172 本文出自: [HansChen的博客] 概述 怎样使用 为项目加入依赖 指定RobolectricTestRunner为执行器 什么是Shadow类 Config配置 配置SDK版本号 配置Application类 指定Resource路径 使用第三方Library Resources 使用限定的资源文件 Properties文件 系统属性配置 驱动Activity生

[译] EXTENDING JQUERY – 2.2 A simple plugin

2.2 一个简单的插件示例 jQuery 插件能做任何事情,这个已经由浩如烟海的各类第三方插件如证明.小到只影响一个元素,大到改变多个元素的外观和行为,jQuery 的各种功能等你来扩展. 2.2.1 占位文本插件 为了维持一个form 的空间,很多时候一个字段的描述往往是省略的,取而代之的是用一个占位文本.如果这个字段是空的,占位文本将会重新显示.为了更好的用户体验,这个占位文本往往是灰色的,用来区别真正的内容.这个功能有个比较通用的名字叫做水印(watermark). 占位的文本可以在插件初