你应该知道的android单元测试

介绍

  • setup:即new 出待测试的类,设置一些前提条件

  • 执行动作:即调用被测类的被测方法,并获取返回结果

  • 验证结果:验证获取的结果跟预期的结果是一样的

Junit4

java测试框架

testCompile ‘junit:junit:4.12’
@Before
@Test
(expected = IllegalArgumentException.class) 验证是否抛该异常
@After
@Ignore 跑所有测试方法忽略该方法

除了在AndroidStudio里面运行,你还可以在命令行通过gradle testDebugUnitTest,或者是gradle testReleaseUnitTest,分别运行debug和release版本的unit testing

Mockito的

  • java界使用最广法的mock框架
    概念就是创建一个类的虚假对象,在测试环境中,用来替换掉真实的

  • 添加依赖

repositories { jcenter() }
dependencies {
      testCompile "org.mockito:mockito-core:
}
  • api

    1. 验证方法调用:
      Mockito.verify(objectToVerify,Mockito.times(3)).methodToVerify(Mockito.anyString());

    2. 设定返回值,方便测试:
      Mockito.when(mockObject.targetMethod(args)).thenReturn(desiredReturnValue);

    3. 执行特定动作,如访问网络数据
    Mockito.doAnswer(desiredAnswer).when(mockObject).targetMethod(args);
    Mockito.doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        //这里可以获得传给performLogin的参数
        Object[] arguments = invocation.
        //callback是第三个参数
        NetworkCallback callback = (NetworkCallback) arguments[
    
        callback.onFailure(500, "Server error");
         return 500;
        }
    }).when(mockUserManager).performLogin(anyString(), anyString(), any(NetworkCallback.class));

    ps: Mockito.spy与mock的唯一区别就是默认行为不一样:spy对象的方法默认调用真实的逻辑,mock对象的方法默认什么都不做,或直接返回默认值。

dagger2

能不用就不用!
- 依赖

buildscript {
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        //添加apt插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

...
```
//应用apt插件
apply plugin: 'com.neenbedankt.android-apt'

...

dependencies {
    ...
    //引入dagger2
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    //java注解
    provided 'org.glassfish:javax.annotation:10.0-b28'
}
``````
  • 依赖注入概念
    我们平常使用的构造函数,需要传入对象去使用,就算是一种依赖注入,然而当我们需要的对象嵌套越来越多的时候,就会显得冗余,这个时候dagger2就出现了。

    client –> Component(工厂管理员)–>Module(生产依赖的工厂)–>Dependency

  • api

    Module 
           @Module 修饰类
           @Provides 修饰方法
           @Singleton 修饰方法,获取单例节省资源
    Component
          @Component
                (modules={OneModule.class})  修饰类,指定管理的生产Dependency的工厂
          1. 定义返回Dependency的抽象方法即可
          2. 先在Component 定义inject(Object obj方法
             定义成员变量@Inject修饰即可
          ps: 不能继承,都要实现inject(this)方法才能生成实例
    
  • 单元测试

//需要测试
public class LoginActivity extends AppCompatActivity {
    @Inject
    LoginPresenter mLoginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ComponentHolder.getAppComponent().inject(this);

        findViewById(R.id.login).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String username = ((EditText) findViewById(R.id.username)).getText().toString();
                String password = ((EditText) findViewById(R.id.password)).getText().toString();

                mLoginPresenter.login(username, password);
            }
        });
    }
}
//测试
public class DaggerUtils {
   public static final AppModule appModule = spy(new AppModule(RuntimeEnvironment.application));

   public static void setupDagger() {
       AppComponent appComponent = DaggerAppComponent.builder().appModule(appModule).build();
       ComponentHolder.setAppComponent(appComponent);
   }
}
//-------
@RunWith(RobolectricGradleTestRunner.class) //Robolectric相关,看不懂的话忽略
@Config(constants = BuildConfig.class, sdk = 21) //同上
public class LoginActivityTest {

    @Test
    public void testActivityStart() {
        @Test
        public void testActivityStart() {
            DaggerUtils.setupDagger();

            LoginPresenter mockLoginPresenter = mock(LoginPresenter.class);  
            Mockito.when(DaggerUtils.appModule.provideLoginPresenter(any(UserManager.class), any(PasswordValidator.class))).thenReturn(mockLoginPresenter);  

            LoginActivity loginActivity = Robolectric.setupActivity(LoginActivity.class);
            ((EditText) loginActivity.findViewById(R.id.username)).setText("xiaochuang");
            ((EditText) loginActivity.findViewById(R.id.password)).setText("xiaochuang is handsome");
            loginActivity.findViewById(R.id.login).performClick();    
            verify(mockLoginPresenter).login("xiaochuang", "xiaochuang is handsome");  //pass!
        }
    }
}

Robolectric使用

Robolectric就是一个能够让我们在JVM上跑测试时够调用安卓的类的框架
- android.jar不完整,android相关方法只是抛出异常RuntimeException(“stub!!”)
- 依赖

testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.2.1"

- api

```
@RunWith(RobolectricGradleTestRunner.class)  
@Config(constants = BuildConfig.class, sdk = 21)  
public class MainActivityTest {  
    @Test  
    public void testMainActivity() {  
        MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);  
        mainActivity.findViewById(R.id.textView1).performClick();  

        Intent expectedIntent = new Intent(mainActivity, SecondActivity.class);  
        ShadowActivity shadowActivity = Shadows.shadowOf(mainActivity);  
        Intent actualIntent = shadowActivity.getNextStartedActivity();  
        Assert.assertEquals(expectedIntent, actualIntent);  
    }  
}  
```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值