Android Studio环境下Android单元测试(基于Robolectric+Mockito)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ruyi366/article/details/51693690

Android的单元测试不需要运行App,所有的任务都交给Robolectric和Mockito去做,简单方便。

1、Robolectric

1.1 基本设置


在Android Studio下的build.gradle添加:

testCompile "org.robolectric:robolectric:3.1"


之后就能想写普通的JUnit测试一样去编写单元测试了。需要注意:Android Studio小于2.0的版本,要支持单元测试需要设置“Build Variants”,路径是“View -->Tool Windows-->Build Variants”,然后设置为“Unit Tests”;当版本为2.0时,默认就支持。

Android Enable Unit Tests


1.2 Shadow

Robolectric定义了大量的Shadow类,修改或者扩展了Android OS类的行为。当一个Android OS类被实例化,Robolectric会搜索相应的Shadow类;如果找到了,将创建与之关联的Shadow对象。Android OS方法每次被调用时,Robolectirc确保:如果存在,Shadow类中的相应方法先被调用,这样就有机会做测试相关逻辑。这种策略可运用于所有的方法,包括static和final方法


另外还可以自定义Shadow,为自定义类提供Shadow方法:

@Implements(ImageView.class)
public class ShadowImageView extends ShadowView {
  ...   
  @Implementation
  public void setImageResource(int resId) {
    // implementation here.
  }
}
以上代码也可以不继承于ShadowView。为了让Robolectric知道自定义的Shadow类,需要使用@Config(shadows=ShadowImageView.class)注解测试方法或者类,或者创建一个文件org.robolectric.Config.properties文件中包含shadows=my.package.ShadowFoo。

2、Mockito

Robolectric在文档中声称:“No Mocking Frameworks Required”:对于Robolectric的另一种可选方法是使用mock框架,比如Mockito;或者模拟出Android SDK。虽然这是个有效的方法,但基本上是应用代码的反向实现。

Mockito虽然不能模拟final类、匿名类和Java基本类型;对于final方法和static方法,不能对其 when(…).thenReturn(…) 操作。另外mock对象,大多都需要植入到应用代码中,从而进行verify(...)操作;但应用代码中不一定有相应的set方法,如果要植入,就需要为了测试添加应用代码。

因此觉得把两者结合起来,发挥各自所长,简单方便。

3、实例

@Implements(AuthManager.class)
public class ShadowAuthManager {
    private static AuthManager instance = mock(AuthManager.class);

    @Implementation
    public boolean hasAuth(String authCode) {
        return instance.hasAuth(authCode);
    }

    @Implementation
    public synchronized static AuthManager getInstance() {
        return instance;
    }
}

AuthManager用于验证当前用户是否有某个权限,如上代码定义了相应的Shadow类,并在类中使用mock实例化对象,在测试时,通过when(...).thenReturn(...)返回不同值,实现不同的测试条件。

    @Test
    @Config(shadows = ShadowAuthManager.class)
    public void should_show_toast_when_click_cashier_without_auth() throws Exception {
        AuthManager mockAuthManager = AuthManager.getInstance();
        when(mockAuthManager.hasAuth(...)).thenReturn(false);

        View view = activity.findViewById(R.id.get_money);
        view.performClick();

        CalmToastView toast = (CalmToastView) ShadowToast.getLatestToast();

        assertEquals(activity.getString(R.string.no_authority), toast.getMessage());
    }

    @Test
    @Config(shadows = ShadowAuthManager.class)
    public void should_goto_cashier_activity_when_click_cashier_with_auth() throws Exception {
        AuthManager mockAuthManager = AuthManager.getInstance();
        when(mockAuthManager.hasAuth(...)).thenReturn(true);

        View view = activity.findViewById(R.id.get_money);
        view.performClick();

        ShadowApplication application = shadowOf(RuntimeEnvironment.application);
        assertEquals("......", application.getNextStartedActivity().getComponent().getClassName());
    }

参考文献:http://robolectric.org/getting-started/


展开阅读全文

没有更多推荐了,返回首页