注册/登录

HarmonyOS非UI单元测试在DevEco Studio上的应用

开发 前端 OpenHarmony
单元测试是测试某个类的某个方法能否正常工作的一种手段。单元测试的粒度:一般一个public方法需要一个test case。

[[415057]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

一、什么是单元测试

单元测试是测试某个类的某个方法能否正常工作的一种手段。

单元测试的粒度:一般一个public方法需要一个test case

二、单元测试目的

  • 验收(改动和重构)
  • 快速验证逻辑
  • 优化代码设计
  • 三、单元测试工具

    junit4 + mockito + powermock

    junit4:JUnit是Java最基础的测试框架,主要的作用就是断言

    Mock的作用:解决测试类对其他类的依赖问题。Mock的类所有方法都是空,所有变量都是初始值。

    PowerMock:PowerMock是Mockito的扩展增强版,支持mock private、static、final方法和类,还增加了很多反射方法可以方便修改静态和非静态成员等。功能比Mockito增加很多。

    1. // build.gradle中引入powermock 
    2. testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' 
    3. testImplementation 'org.powermock:powermock-module-junit4:2.0.2' 

    四、单元测试流程

    1、新建测试类(快捷导航键: ctrl+shift+T),新建测试用例名

    2、setUp 初始化一些公共的东西

    3、编写测试代码,执行操作

    4、验证结果

    一般我们依据被测方法是否有返回值选用不同的验证方法。

    有返回值的,直接调用该方法得到返回结果,使用JUnit的Asset验证结果;

    没有返回值的,则看方法最终调用了依赖对象的哪个方法,然后再校验依赖对象的该方法有没有被调用,以及获取到的参入参数是否正确

    举例说明:

    1. public void login(String username, String password) { 
    2.      if (username == null || username.length() == 0) { 
    3.          return
    4.        } 
    5.      if (password == null || password.length() < 6) { 
    6.          return
    7.        } 
    8.      mUserManager.performLogin(username, password); 
    9.  } 

    我们要验证该login方法是否正确,则依据传入的参数,判断mUserManager的performLogin方法是否得要了调用。

    五、基础用法

    常见注解:

  • @Before: 如果一个方法被@Before修饰过了,那么在每个测试方法调用之前,这个方法都会得到调用。
  • @After: 每个测试方法运行结束之后,会得到运行的方法
  • @Test:如果一个方法被@Before修饰过了,那么这个方法为可执行的测试用例,注解设置expected参数 可验证一个方法是否抛出了异常
  • @Ignore:忽略的测试方法
  • @RunWith 指定该测试类使用某个运行器
  • @Rule:重新制定测试类中方法的行为,可以理解为在测试用例执行前和执行后插桩
  • @Mock: 创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的:
  • a.验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等

    b.指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作

    注意:mock出来的对象并不会自动替换掉正式代码里面的对象,你必须要有某种方式把mock对象应用到正式代码里面

    junit框架中Assert类的常用方法

  • assertEquals: 断言传入的预期值与实际值是相等的
  • assertNotEquals: 断言传入的预期值与实际值是不相等的
  • assertArrayEquals: 断言传入的预期数组与实际数组是相等的
  • assertNull: 断言传入的对象是为空
  • assertTrue: 断言条件为真
  • assertFalse: 断言条件为假
  • assertSame: 断言两个对象引用同一个对象,相当于“==”
  • Mockito的使用

    Mockito的使用主要分三步:Mock/spy对象 + 打桩 + 验证

    1. when(mockObj.methodName(params)).thenReturn(result) 
  • mock: 所有方法都是空方法,非void方法都将返回默认值,比如int方法返回0,对象方法将返回null,而void方法将什么都不做。 适用于类对外部依赖较多,只关新少数函数的具体实现;
  • spy:跟正常类对象一样,是正常对象的替身。适用场景跟mock相反,类对外依赖较少,关心大部分函数的具体实现。
  • 四种Mock方式:

  • 普通方法:
    1. @Test 
    2. public void testIsNotNull(){ 
    3.     Person mPerson = mock(Person.class); //<--使用mock方法 
    4.  
    5.    assertNotNull(mPerson); 
  • 注解方法:
    1. public class MockitoAnnotationsTest { 
    2.  
    3.     @Mock //<--使用@Mock注解 
    4.     Person mPerson; 
    5.  
    6.     @Before 
    7.     public void setup(){ 
    8.         MockitoAnnotations.initMocks(this); //<--初始化 
    9.     } 
    10.  
    11.     @Test 
    12.     public void testIsNotNull(){ 
    13.         assertNotNull(mPerson); 
    14.     } 
    15.  
  • 运行器方法:
    1. @RunWith(MockitoJUnitRunner.class) //<--使用MockitoJUnitRunner 
    2. public class MockitoJUnitRunnerTest { 
    3.  
    4.     @Mock //<--使用@Mock注解 
    5.     Person mPerson; 
    6.  
    7.     @Test 
    8.     public void testIsNotNull(){ 
    9.         assertNotNull(mPerson); 
    10.     } 
  • MockitoRule方法:
    1. public class MockitoRuleTest { 
    2.  
    3.     @Mock //<--使用@Mock注解 
    4.     Person mPerson; 
    5.  
    6.     @Rule //<--使用@Rule 
    7.     public MockitoRule mockitoRule = MockitoJUnit.rule(); 
    8.  
    9.     @Test 
    10.     public void testIsNotNull(){ 
    11.         assertNotNull(mPerson); 
    12.     } 
    13.  

    常用参数匹配

  • anyObject() 匹配任何对象
  • any(Class type) 与anyObject()一样
  • any() 与anyObject()一样 (慎用,有些场景会导致测试用例执行失败)
  • anyBoolean() 匹配任何boolean和非空Boolean
  • anyByte() 匹配任何byte和非空Byte
  • anyInt() 匹配任何int和非空Integer
  • anyString() 匹配任何非空String
  • 常用打桩方法

  • thenReturn(T value) 设置要返回的值
  • thenThrow(Throwable… throwables) 设置要抛出的异常
  • thenAnswer(Answer answer) 对结果进行拦截
  • doReturn(Object toBeReturned) 提前设置要返回的值
  • doThrow(Throwable… toBeThrown) 提前设置要抛出的异常
  • doAnswer(Answer answer) 提前对结果进行拦截
  • doCallRealMethod() 调用某一个方法的真实实现
  • doNothing() 设置void方法什么也不做
  • PowerMock使用

    首先使用PowerMock必须加注解@PrepareForTest和@RunWith(PowerMockRunner.class)。注解@PrepareForTest里写的是静态方法所在的类,如果@RunWith被占用。这时我们可以使用@Rule来解决

    1. @Rule 
    2. public PowerMockRule rule = new PowerMockRule(); 
  • mock静态方法
    1. @RunWith(PowerMockRunner.class) 
    2. public class PowerMockitoStaticMethodTest { 
    3.  
    4.     @Test 
    5.     @PrepareForTest({Banana.class}) 
    6.     public void testStaticMethod() {  
    7.         PowerMockito.mockStatic(Banana.class); //<-- mock静态类 
    8.         Mockito.when(Banana.getColor()).thenReturn("绿色"); 
    9.         Assert.assertEquals("绿色", Banana.getColor()); 
    10.  
    11.         //更改类的私有属性 
    12.         Whitebox.setInternalState(Banana.class, "COLOR""红色的"); 
    13.     } 
  • mock私有方法
    1. @RunWith(PowerMockRunner.class) 
    2. public class PowerMockitoPrivateMethodTest { 
    3.  
    4.     @Test 
    5.     @PrepareForTest({Banana.class}) 
    6.     public void testPrivateMethod() throws Exception { 
    7.         Banana mBanana = PowerMockito.mock(Banana.class); 
    8.         PowerMockito.when(mBanana.getBananaInfo()).thenCallRealMethod(); 
    9.         PowerMockito.when(mBanana, "flavor").thenReturn("苦苦的"); 
    10.         Assert.assertEquals("苦苦的黄色的", mBanana.getBananaInfo()); 
    11.         //验证flavor是否调用了一次 
    12.         PowerMockito.verifyPrivate(mBanana).invoke("flavor");  
    13.     } 
  • mock final方法,使用方式同 mock 私有方法
  • mock 构造方法
    1. @Test 
    2. @PrepareForTest({Banana.class}) 
    3. public void testNewClass() throws Exception { 
    4.     Banana mBanana = PowerMockito.mock(Banana.class); 
    5.     PowerMockito.when(mBanana.getBananaInfo()).thenReturn("大香蕉"); 
    6.     //如果new新对象,则返回这个上面设置的这个对象 
    7.     PowerMockito.whenNew(Banana.class).withNoArguments().thenReturn(mBanana); 
    8.     //new新的对象 
    9.     Banana newBanana = new Banana(); 
    10.     Assert.assertEquals("大香蕉", newBanana.getBananaInfo()); 

    @Rule用法

    自定义@Rule很简单,就是实现TestRule 接口,实现apply方法。

    1. public class MyRule implements TestRule { 
    2.  
    3.     @Override 
    4.     public Statement apply(final Statement base, final Description description) { 
    5.  
    6.         return new Statement() { 
    7.             @Override 
    8.             public void evaluate() throws Throwable { 
    9.                 // evaluate前执行方法相当于@Before 
    10.                 String methodName = description.getMethodName(); // 获取测试方法的名字 
    11.                 System.out.println(methodName + "测试开始!"); 
    12.  
    13.                 base.evaluate();  // 运行的测试方法 
    14.  
    15.                 // evaluate后执行方法相当于@After 
    16.                 System.out.println(methodName + "测试结束!"); 
    17.             } 
    18.         }; 
    19.     } 
    20.  

    六、RxJava与单元测试

    RxJava的火热程度不用多说,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大开发者的欢迎。我们经常用它来进行线程的切换操作

    1. public void threadSwitch() { 
    2.       Observable.just("one""two""three""four""five"
    3.               .subscribeOn(Schedulers.newThread()) 
    4.               .observeOn(OpenHarmonySchedulers.mainThread()) 
    5.               .subscribe(new Observer<String>() { 
    6.                   @Override 
    7.                   public void onSubscribe(@NonNull Disposable d) { 
    8.  
    9.                   } 
    10.  
    11.                   @Override 
    12.                   public void onNext(@NonNull String s) { 
    13.                       System.out.println(s); 
    14.                       if (callBack != null) { 
    15.                           callBack.success(s); 
    16.                       } 
    17.                   } 
    18.  
    19.                   @Override 
    20.                   public void onError(@NonNull Throwable e) { 
    21.                       if (callBack != null) { 
    22.                           callBack.failed(); 
    23.                       } 
    24.                   } 
    25.  
    26.                   @Override 
    27.                   public void onComplete() { 
    28.  
    29.                   } 
    30.               }); 
    31.   } 

    Observable.just执行在子线程中, callBack回调执行在主线程中

    基于mockito,我们直接写出对应的单元测试代码:

    1. @Test 
    2. public void threadSwitch() { 
    3.     presenter.threadSwitch(); 
    4.     // 验证callBack的success方法被调用了5次 
    5.     verify(callBack,times(5)).success(anyString()); 

    执行此用例,我们会发现它会报如下错误:

    1. java.lang.ExceptionInInitializerError 
    2.   at io.reactivex.rxjava3.openharmony.schedulers.OpenHarmonySchedulers.lambda$static$0(Unknown Source) 
    3.   at io.reactivex.rxjava3.openharmony.plugins.RxOpenHarmonyPlugins.callRequireNonNull(Unknown Source) 
    4.   at io.reactivex.rxjava3.openharmony.plugins.RxOpenHarmonyPlugins.initMainThreadScheduler(Unknown Source) 
    5.   at io.reactivex.rxjava3.openharmony.schedulers.OpenHarmonySchedulers.<clinit>(Unknown Source) 
    6.   at kale.ui.shatter.test.RxSchedulerPresenter.threadSwitch(RxSchedulerPresenter.java:65) 
    7.   at kale.ui.shatter.test.RxSchedulerTestTest.threadSwitch(RxSchedulerTestTest.java:52) 
    8.   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    9.   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    10.   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    11.   at java.lang.reflect.Method.invoke(Method.java:498) 
    12.   at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) 
    13.   at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    14.   at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) 
    15.   at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    16.   at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    17.   at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) 
    18.   at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) 
    19.   at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) 
    20.   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) 
    21.   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) 
    22.   at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) 
    23.   at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) 
    24.   at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) 
    25.   at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) 
    26.   at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) 
    27.   at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) 
    28.   at org.junit.runners.ParentRunner.run(ParentRunner.java:413) 
    29.   at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79) 
    30.   at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85) 
    31.   at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39) 
    32.   at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163) 
    33.   at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
    34.   at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) 
    35.   at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) 
    36.   at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) 
    37.   at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) 
    38.   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    39.   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    40.   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    41.   at java.lang.reflect.Method.invoke(Method.java:498) 
    42.   at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:128) 
    43. Caused by: java.lang.RuntimeException: Stub! 
    44.   at ohos.eventhandler.EventRunner.getMainEventRunner(EventRunner.java:110) 
    45.   at io.reactivex.rxjava3.openharmony.schedulers.OpenHarmonySchedulers$MainHolder.<clinit>(Unknown Source) 
    46.   ... 41 more 

    那么怎么解决呢?那就是设置用到的Schedulers.进行hook,修改用例如下:

    1. @Test 
    2.  public void threadSwitch() { 
    3.      RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    4.      RxJavaPlugins.setComputationSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    5.      RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    6.      RxOpenHarmonyPlugins.setInitMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    7.  
    8.      presenter.threadSwitch(); 
    9.  
    10.      // 验证callBack的success方法被调用了5次 
    11.      verify(callBack,times(5)).success(anyString()); 
    12.  } 

    原理就是当进行线程调度时,都让它切换到Schedulers.trampoline(),这样我们就能正确的输出了。但通常情况下,我们使用到线程切换的场景会很多,这样写毕竟还是不够优雅,稍后我会给出更好的解决方式。

    除了上面的线程切换场景,我们还经常会使用到时间轮询之类的场景,例如:

    1. public void interval() { 
    2.        Observable.interval(1, TimeUnit.SECONDS) 
    3.                .take(5) 
    4.                .flatMap((Function<Long, ObservableSource<String>>) 
    5.                        aLong -> Observable.just(aLong + "")) 
    6.                .subscribeOn(Schedulers.newThread()) 
    7.                .observeOn(OpenHarmonySchedulers.mainThread()) 
    8.                .subscribe(new Observer<String>() { 
    9.                    @Override 
    10.                    public void onSubscribe(@NonNull Disposable d) { 
    11.  
    12.                    } 
    13.  
    14.                    @Override 
    15.                    public void onNext(@NonNull String s) { 
    16.                        System.out.println(s); 
    17.                        if (callBack != null) { 
    18.                            callBack.success(s); 
    19.                        } 
    20.                    } 
    21.  
    22.                    @Override 
    23.                    public void onError(@NonNull Throwable e) { 
    24.                        if (callBack != null) { 
    25.                            callBack.failed(); 
    26.                        } 
    27.                    } 
    28.  
    29.                    @Override 
    30.                    public void onComplete() { 
    31.  
    32.                    } 
    33.                }); 
    34.    } 

    我们每隔1秒发射一次数据,一共发送5次,我们写出以下单元测试:

    1. @Test 
    2.    public void interval() { 
    3.        RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    4.        RxJavaPlugins.setComputationSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    5.        RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    6.        RxOpenHarmonyPlugins.setInitMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline()); 
    7.         
    8.        presenter.interval(); 
    9.  
    10.        // 验证callBack的success方法被调用了5次 
    11.        verify(callBack,times(5)).success(anyString()); 
    12.    } 

    使用上面线程异步变同步的方法确实可以进行测试,但是需要等到5秒后才能执行完成,这显然不符合单元测试执行快的特点。这里,RxJava给我们提供了TestScheduler,调用TestScheduler的advanceTimeTo或advanceTimeBy方法来进行时间操作。

    1. @Test 
    2.    public void interval() { 
    3.        TestScheduler testScheduler = new TestScheduler(); 
    4.        RxJavaPlugins.setIoSchedulerHandler(scheduler -> testScheduler); 
    5.        RxJavaPlugins.setComputationSchedulerHandler(scheduler -> testScheduler); 
    6.        RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> testScheduler); 
    7.        RxOpenHarmonyPlugins.setInitMainThreadSchedulerHandler(scheduler -> testScheduler); 
    8.        presenter.interval(); 
    9.        //将时间设到3秒后 
    10.        testScheduler.advanceTimeTo(3,TimeUnit.SECONDS); 
    11.        verify(callBack,times(3)).success(anyString()); 
    12.        //将时间设到10秒后 
    13.        testScheduler.advanceTimeTo(10,TimeUnit.SECONDS); 
    14.        verify(callBack,times(5)).success(anyString()); 
    15.    } 

    这样我们就不用每次执行到该用例的时候,还得等待设定的时间。每次这样写毕竟也不够优雅,下面我给出基于rxjava3和Rxohos:1.0.0,使用TestRule来进行RxJava线程切换及时间操作的工具类,供大家参考:

    1. /** 
    2.  * Created by xiongwg on 2021-07-08. 
    3.  * <p> 
    4.  * 这个类是让Obserable从异步变同步。 
    5.  * 
    6.  * 注意: 当有操作时间的测试时,必须调用{@link #setScheduler(Scheduler)}方法 
    7.  */ 
    8.  
    9. public class RxJavaTestSchedulerRule implements TestRule { 
    10.      /** 
    11.      * 运行在当前线程,可异步变同步 
    12.      */ 
    13.     public static final Scheduler DEFAULT_SCHEDULER = Schedulers.trampoline(); 
    14.  
    15.     /** 
    16.      * 操作时间类的  Scheduler 
    17.      */ 
    18.     public static final Scheduler TIME_SCHEDULER = new TestScheduler(); 
    19.  
    20.  
    21.     private Scheduler mScheduler = DEFAULT_SCHEDULER; 
    22.  
    23.  
    24.     /** 
    25.      * 切换 Scheduler 
    26.      * 
    27.      * @param scheduler 单元测试用例执行所在的 Scheduler 
    28.      */ 
    29.     public void setScheduler(Scheduler scheduler) { 
    30.         if (scheduler != mScheduler) { 
    31.             mScheduler = scheduler; 
    32.             resetTestSchecduler(); 
    33.         } 
    34.     } 
    35.  
    36.     @Override 
    37.     public Statement apply(final Statement base, Description description) { 
    38.         return new Statement() { 
    39.             @Override 
    40.             public void evaluate() throws Throwable { 
    41.                 resetTestSchecduler(); 
    42.                 base.evaluate(); 
    43.             } 
    44.         }; 
    45.     } 
    46.  
    47.  
    48.     public void advanceTimeBy(long delayTime, TimeUnit unit) { 
    49.         if (mScheduler instanceof TestScheduler) { 
    50.             ((TestScheduler) mScheduler).advanceTimeBy(delayTime, unit); 
    51.         } 
    52.     } 
    53.  
    54.     public void advanceTimeTo(long delayTime, TimeUnit unit) { 
    55.         if (mScheduler instanceof TestScheduler) { 
    56.             ((TestScheduler) mScheduler).advanceTimeTo(delayTime, unit); 
    57.         } 
    58.     } 
    59.  
    60.     public void triggerActions() { 
    61.         if (mScheduler instanceof TestScheduler) { 
    62.             ((TestScheduler) mScheduler).triggerActions(); 
    63.         } 
    64.     } 
    65.  
    66.     private void resetTestSchecduler() { 
    67.         RxJavaPlugins.reset(); 
    68.         RxJavaPlugins.setIoSchedulerHandler(scheduler -> mScheduler); 
    69.         RxJavaPlugins.setComputationSchedulerHandler(scheduler -> mScheduler); 
    70.         RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> mScheduler); 
    71.  
    72.         RxOpenHarmonyPlugins.reset(); 
    73.         RxOpenHarmonyPlugins.setInitMainThreadSchedulerHandler(scheduler -> mScheduler); 
    74.     } 

    使用起来很简单

    1. // 1、声明RxJavaTestSchedulerRule Rule 
    2.  @Rule 
    3.  public RxJavaTestSchedulerRule rxJavaTestSchedulerRule = new RxJavaTestSchedulerRule(); 
    4.  @Test 
    5.  public void interval() { 
    6.      //2、在需要进行时间操作的方法前,设置Scheduler为TIME_SCHEDULER 
    7.      rxJavaTestSchedulerRule.setScheduler(TIME_SCHEDULER); 
    8.      presenter.interval(); 
    9.      //3、操作时间,将时间设置为3秒后 
    10.      rxJavaTestSchedulerRule.advanceTimeTo(3, TimeUnit.SECONDS); 
    11.      verify(callBack,times(3)).success(anyString()); 
    12.      //将时间设置为10秒后 
    13.      rxJavaTestSchedulerRule.advanceTimeTo(10, TimeUnit.SECONDS); 
    14.      verify(callBack,times(5)).success(anyString()); 
    15.  } 

    Java单元测试中引入了ohos相关类的解决方案

    1、尝试Mock出该对象

    2、在java单元测试包下新建同包名同类名的Java文件,重写调用到的方法

    项目本地查看测试覆盖率

    右击需要测试覆盖率的包名 ==> 点击“run test in ‘xxx’ with Coverage”

    责任编辑:jianghua 鸿蒙社区
    点赞
    收藏