单元测试-踩坑指南

单元测试中经常碰到的问题:

  1. Android依赖
  2. 内部new对象如何处理?
  3. 本地方法怎么隔离?
  4. RxJava异步如何处理?

前提:引入Mockito、PowerMock等第三方测试框架,对测试对象进行模拟操作。

一、代码中用到了TextUtil.isEmpty()的如何测试?
1
2
3
4
5
6
public static boolean isValidEmail(CharSequence email) {
if (TextUtils.isEmpty(email)) {
return false;
}
return EMAIL_PATTERN.matcher(email).matches();
}

当测试这个方法时,就会报错,

1
java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked.

这种情况,直接在本地测试目录(app/src/test/java)下添加TextUtils类的实现,但必须保证包名相同。

1
2
3
4
5
6
7
package android.text;
public class TextUtils {
public static boolean isEmpty(CharSequence str) {
return str == null || str.length() == 0;
}
}
二、native方法隔离
1
2
3
public class Model {
public native boolean nativeMethod();
}

进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ModelTest {
Model model;
@Before
public void setUp() throws Exception {
model = mock(Model.class);
}
@Test
public void testNativeMethod() throws Exception {
when(model.nativeMethod()).thenReturn(true);
Assert.assertTrue(model.nativeMethod());
}
}
三、内部new对象如何处理?
1
2
3
4
5
6
7
8
9
10
public class Presenter {
Model model;
public Presenter() {
model = new Model();
}
public boolean getBoolean() {
return model.getBoolean());
}
}

改变写法。

1
2
3
4
5
6
7
8
9
public class Presenter {
Model model;
public Presenter(Model model) {
this.model = model;
}
public boolean getBoolean() {
return model.getBoolean();
}
}

进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PresenterTest {
Model model;
Presenter presenter;
@Before
public void setUp() throws Exception {
// mock Model对象
model = mock(Model.class);
presenter = new Presenter(model);
}
@Test
public void testGetBoolean() throws Exception {
when(model.getBoolean()).thenReturn(true);
Assert.assertTrue(presenter.getBoolean());
}
}
四、Rxjava异步如何处理?

异步的话单元测试就无法测试了。那么就必须同步情况下才可以测试,开发RxJava的大神早就料到了,于是乎可以他通过立即执行就可以了

1
Schedulers.immediate()

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class RxTools {
public static void asyncToSync() {
Func1<Scheduler, Scheduler> schedulerFunc = new Func1<Scheduler, Scheduler>() {
@Override
public Scheduler call(Scheduler scheduler) {
return Schedulers.immediate();
}
};
RxAndroidSchedulersHook rxAndroidSchedulersHook = new RxAndroidSchedulersHook() {
@Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
};
RxJavaHooks.reset();
RxJavaHooks.setOnIOScheduler(schedulerFunc);
RxJavaHooks.setOnComputationScheduler(schedulerFunc);
RxAndroidPlugins.getInstance().reset();
RxAndroidPlugins.getInstance().registerSchedulersHook(rxAndroidSchedulersHook);
}
}

小结

归根结底最主要的就是进行依赖隔离。单元测试,验证的是逻辑是否正确,忽略数据的变化。

Neil Liu wechat
个人微信,欢迎交流
让我感受下知识的力量~