设为首页 加入收藏

TOP

[Android]使用自定义JUnit Rules、annotations和Resources进行单元测试(翻译)(二)
2017-10-13 10:35:43 】 浏览:2603
Tags:Android 使用 定义 JUnit Rules annotations Resources 进行 单元 测试 翻译
a resources

Java resources是程序需要的数据文件,它被放置在源代码外面。注意我们讨论的是 Java resources,默认被放置在src/<source set>/resources,并不是 Android App Resources(drawables, layouts等)。这本例子中并没有Android特别的特性。所以一切都是可以像 Robolectric 那样脱离frameworks可单元测试的。

如果listing 6的JSON文件被保存于src/test/resources/pl/droidsonroids/modeltesting/api/contributors.json,它可以通过调用TestClass.getResourceAsStream("contributors.json")来被单元测试代码访问。相关的类需要被放置在对应的package中,在这个例子中是pl.droidsonroids.modeltesting.api。详情见#getResourceAsStream() javadoc

注解Annotation

Annotation是关联到源代码元素的元数据(eg. 方法或者类)。有众所周知的一些如@Override@Deprecated的内置注解。也可以自定义并使用它们把特定的resources绑定到测试方法中。

注解来起来与interface很类似:

Java

@Retention(RUNTIME)
@Target(METHOD)
public @interface JsonFileResource {
    String fileName();
    Class<?> clazz();
}

Listing 7. 简单注解.

注意interface关键字前面的@符号。我们自定义的注解被2个元注解来注解。我们设置RetentionRUNTIME,因为注解需要在单元测试执行时(运行时)为可读,所以默认的retention(CLASS)的并不满足。我们也需要设置TargetMETHOD因为我们只需要为方法进行注解(绑定特定的resource)。错位的注解会引发编译错误。没有指定一个target,注解会可以被用于任何地方。

JUnit Rules

简单来说,rule是在测试(方法)运行时触发的一个hook。我们将使用rule在测试方法执行之前增加一些额外的行为。即我们将从resources中解析JSON并提供给测试方法内部相应的POJO。我们的目标时像下面这样支持单元测试:

@Rule public JsonParsingRule jsonParsingRule = new JsonParsingRule(Constants.GSON);
 
@Test
@JsonFileResource(fileName = "contributors.json", clazz = Contributor[].class)
public void testGetContributors() throws Exception {
 Contributor[] contributors = jsonParsingRule.getValue();
 assertThat(contributors).hasSize(2);
 assertThat(contributors[0].login).isEqualTo("koral--");
}

Listing 8. 使用自定义rule的简单测试方法.

如你所见,模版代码与listing 4相比明显地减少。只有必要的部分是类型明确的:

  • GSON实例用来解析JSONs - jsonParsingRule = new JsonParsingRule(Constants.GSON)

  • 被放置JSON字符串的resource - @JsonFileResource(fileName = "contributors.json"

  • POJO类 - , clazz = Contributor[].class

  • POJO实例的接收 - contributors = jsonParsingRule.getValue()

注意对于测试类只需要一个JsonParsingRule实例。对于每个测试方法Rule会被独立计算并且在特定方法中jsonParsingRule.getValue()的结果不会影响到上一次测试。clazz并不是一个错字而是故意的,因为class是Java语言关键字并不能用做一个标识符。还有一个重要的是被@Rule注解的属性必须是public和非static的。

Rule实现

看下rule实现的草案:

public class JsonParsingRule implements TestRule {
 private final Gson mGson;
 private Object mValue;
 
 public JsonParsingRule(Gson gson) {
 mGson = gson;
 }
 
 @SuppressWarnings("unchecked")
 public  T getValue() {
 return (T) mValue;
 }
 
 @Override
 public Statement apply(final Statement base, final Description description) {
 return new Statement() {
 @Override
 public void eva luate() throws Throwable {
 //TODO set mValue according to annotation
 base.eva luate();
 }
 };
 }
}

Listing 9. Rule骨架.

我们的rule实现了TestRule,因此可以使用被使用@Rule注解。我们使用了一个范型的getter,所以它的返回值可以被直接分配给特定类型的变量而不需要在测试方法中转型。在apply()方法中我们可以创建一个原始Statement(测试方法)的包装。调用base.eva luate()被放置在最后(在注解处理之后),因此在测试方法执行过程中rule的效果是可见的。

现在更接近地观看statement包装的关键部分(listing 9TODO的实现):

JsonFileResource jsonFileResource = description.getAnnotation(JsonFileResource.class);
if (jsonFileResource != null) {
 Class<?> clazz = jsonFileResource.clazz();
 String resourceName = jsonFileResource.fileName();
 Class<?> testClass = description.getTestClass();
 InputStream in = testClass.getResourceAsStream(resourceName);
 
 assert in != null : "Failed to load resource: &qu
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Android 监听ScrollView的滑动 下一篇标题栏透明度变化

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目