精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

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” 

【中軟國際】HarmonyOS 非UI單元測試在DevEco Studio上的應用-鴻蒙HarmonyOS技術社區

 

項目本地查看測試案例通過率

【中軟國際】HarmonyOS 非UI單元測試在DevEco Studio上的應用-鴻蒙HarmonyOS技術社區
【中軟國際】HarmonyOS 非UI單元測試在DevEco Studio上的應用-鴻蒙HarmonyOS技術社區
【中軟國際】HarmonyOS 非UI單元測試在DevEco Studio上的應用-鴻蒙HarmonyOS技術社區

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2017-03-28 12:25:36

2022-04-08 09:01:56

腳本Go應用單元

2017-01-14 23:42:49

單元測試框架軟件測試

2009-06-23 18:19:32

單元測試Hibernate配置

2022-12-08 08:01:02

Python測試單元

2012-06-18 10:03:46

Visual Stud

2010-08-27 09:11:27

Python單元測試

2021-09-02 15:29:42

鴻蒙HarmonyOS應用

2023-07-26 08:58:45

Golang單元測試

2023-09-21 22:12:06

單元測試數據工程

2021-03-24 09:30:02

Jupyter not單元測試代碼

2011-05-16 16:52:09

單元測試徹底測試

2011-01-25 10:42:29

Visual Stud

2010-10-13 09:29:53

JUnit單元測試Android

2017-01-16 12:12:29

單元測試JUnit

2017-01-14 23:26:17

單元測試JUnit測試

2011-06-14 15:56:42

單元測試

2020-08-18 08:10:02

單元測試Java

2022-05-12 09:37:03

測試JUnit開發

2010-03-02 09:10:41

Visual Stud
點贊
收藏

51CTO技術棧公眾號

亚洲第一页在线| 国产精品福利一区二区三区| 午夜精品久久久久久久久久久久 | 国产特级黄色片| 成人羞羞网站入口免费| 9191国产精品| 日本一本二本在线观看| 日本在线视频站| 成人美女视频在线观看| 国产精品久久久久久久久久久新郎| 色姑娘综合天天| 77thz桃花论族在线观看| 国产欧美一区二区三区在线看蜜臀| 性欧美xxxx视频在线观看| 谁有免费的黄色网址| 日本在线成人| 欧美无人高清视频在线观看| 黄色三级中文字幕| 91最新在线| av网站免费线看精品| 国产精品久久久久久久久久久久| 在线不卡av电影| 国产在线一区不卡| 欧美在线你懂得| 蜜桃传媒一区二区三区| 国产视频在线播放| 国产蜜臀av在线一区二区三区 | 桃花岛tv亚洲品质| 亚洲黄一区二区三区| 日韩免费中文专区| 日韩在线一区二区三区四区| 加勒比av一区二区| 欧美一区二区三区图| 精品少妇theporn| 亚洲精品电影| 影音先锋日韩有码| 亚洲天堂视频一区| 欧美挤奶吃奶水xxxxx| 日韩视频一区二区在线观看| 国产高清视频网站| 日韩电影免费观看高清完整版| 国产欧美视频一区二区| 久久久久se| 亚洲国产视频一区二区三区| 狠狠色综合色综合网络| 国产美女精彩久久| 制服丝袜在线一区| 日韩高清在线一区| 日韩免费高清在线观看| 久久精品视频1| 国产欧美欧美| 91成人在线视频| 日韩毛片在线视频| 99国产精品99久久久久久粉嫩| 亚洲精品视频播放| 国产精品无码一区二区三区免费| 奇米777日韩| 色偷偷88欧美精品久久久| 性高湖久久久久久久久aaaaa| 四虎精品在线| xnxx国产精品| 少妇免费毛片久久久久久久久 | 中老年在线免费视频| 亚洲国产一区二区视频| 日韩精品一区二区免费| 超碰在线资源| 日韩欧美亚洲范冰冰与中字| 97xxxxx| 最新日韩三级| 欧美日韩美少妇| 成人三级做爰av| 日韩美女毛片| 国产一区二区动漫| 亚洲综合视频网站| 红桃视频国产精品| 欧美综合在线第二页| 波多野结衣高清在线| 麻豆成人免费电影| 97人人澡人人爽| 天堂网av在线播放| 国产片一区二区| 51xx午夜影福利| 7777kkk亚洲综合欧美网站| 日韩欧美亚洲成人| 尤物网站在线看| 美女一区二区在线观看| 伊人成人开心激情综合网| 四虎永久免费在线| 99精品视频免费观看| 国产精品久久久久福利| 超碰免费在线97| 久久久五月婷婷| 潘金莲一级淫片aaaaa免费看| 可以在线观看的av| 国产精品黄色在线观看| 97中文字幕在线| 666av成人影院在线观看| 正在播放一区二区| 免费观看一级一片| 婷婷综合在线| 奇米成人av国产一区二区三区| 久久久精品国产sm调教网站| 免费在线欧美黄色| 92国产精品久久久久首页| 污视频在线免费| 成人免费在线观看入口| 男人揉女人奶房视频60分| 亚洲一区二区av| 亚洲精品自拍视频| 国产探花在线免费观看| 日日摸夜夜添夜夜添精品视频| 九色精品免费永久在线| 一级黄色在线观看| 成人一区二区在线观看| 一区二区在线不卡| 一个人看的www视频在线免费观看 一个人www视频在线免费观看 | 红桃视频成人在线观看| 最新天堂在线视频| 噜噜噜狠狠夜夜躁精品仙踪林| 日韩一级高清毛片| 免费看日本黄色片| 国产一区导航| 国产精品日韩欧美一区二区三区| 精品久久久无码中文字幕| 国产欧美一区二区精品性色超碰 | 99日在线视频| 奇米亚洲欧美| 91精品国产99久久久久久| 精品黑人一区二区三区在线观看 | 国产精品久久久| 青青青草原在线| 五月婷婷激情综合网| 性高潮免费视频| 欧美1区2区3区| 国产在线观看精品| 成人免费在线视频网| 日韩欧美在线视频| 久久久久麻豆v国产精华液好用吗| 一本色道69色精品综合久久| 日韩中文字幕免费| 精品国产乱子伦| 91免费在线看| 男人天堂999| 一本久久青青| 日韩免费在线播放| 蝌蚪视频在线播放| 91福利小视频| 成人在线一级片| 日韩精品久久久久久| 欧美亚州在线观看| 肉色欧美久久久久久久免费看| 欧美三级中文字幕在线观看| 一区二区三区伦理片| 99热免费精品在线观看| 久久精品ww人人做人人爽| 成年人黄色大片在线| 日韩精品在线影院| 精品黑人一区二区三区| 欧美韩国日本不卡| 无尽裸体动漫2d在线观看| 91精品精品| 都市激情久久久久久久久久久| 无码国产精品一区二区免费16| 国产调教视频一区| 丰满少妇在线观看| 91欧美大片| aa成人免费视频| 国产拍在线视频| 亚洲系列中文字幕| 91丨porny丨在线中文| 亚洲精品国产精品乱码不99| 美女扒开腿免费视频| 在线一区欧美| 亚洲巨乳在线观看| 日韩第一区第二区| 2019中文在线观看| 国自产拍在线网站网址视频| 欧美日韩一区三区四区| 欧美黑人一级片| 久久综合给合久久狠狠狠97色69| 永久免费看av| 日韩高清电影免费| 国产欧美一区二区白浆黑人| 四虎av在线| 亚洲天堂免费观看| 99国产揄拍国产精品| 欧美视频在线视频| 亚洲女同二女同志奶水| 成人在线综合网站| www.这里只有精品| 亚洲人体偷拍| 在线观看成人av电影| 91蜜桃臀久久一区二区| 国产精品v片在线观看不卡| 国内外激情在线| 亚洲精选一区二区| 国产av无码专区亚洲av| 日韩欧美中文免费| 激情综合五月网| 欧美国产乱子伦| 国产a级黄色片| 久久99在线观看| 国产免费毛卡片| 欧美激情91| 亚洲伊人婷婷| 亚洲午夜久久| 国产传媒一区二区三区| 欧美日韩卡一| 日韩美女福利视频| 91视频欧美| 久久精品视频导航| 电影在线一区| 亚洲精品影视在线观看| 农村少妇久久久久久久| 69堂成人精品免费视频| 四虎影院在线免费播放| 亚洲国产乱码最新视频| 日本精品在线免费观看| 中文字幕国产精品一区二区| 大地资源二中文在线影视观看 | 中文av一区二区| 日韩中文字幕免费在线| 亚洲毛片网站| 久久人人爽人人爽人人av| 五月天综合网站| 一本一本a久久| 精品香蕉视频| 欧美一区免费视频| 欧美在线关看| 精品乱色一区二区中文字幕| 一本一道久久a久久| 97人摸人人澡人人人超一碰| 国产在线不卡一区二区三区| 国产在线高清精品| 欧美视频第一| 国产精品亚洲精品| 日本综合视频| 国产精品国产三级国产专播精品人 | 狠狠干视频网站| 亚洲国产成人精品女人| 伊人天天久久大香线蕉av色| 欧美hd在线| 亚洲成人第一| 清纯唯美日韩| 一级做a爰片久久| 国产精品毛片久久| 欧美aaa在线观看| 911精品美国片911久久久 | 午夜视频在线播放| 亚洲成人黄色在线观看| 亚洲欧美激情另类| 亚洲成人国产精品| 你懂的视频在线| 亚洲欧美日韩在线一区| 国内av一区二区三区| 在线色欧美三级视频| 成人一区二区不卡免费| 久久精品视频网站| 在线观看av免费| 久久久噜久噜久久综合| 涩涩网在线视频| 国产精品美女免费| 99精品美女视频在线观看热舞| 奇米成人av国产一区二区三区| 免费a级人成a大片在线观看| 中文字幕av一区中文字幕天堂 | 国产天堂第一区| 欧美视频一区二区在线观看| 波多野结衣在线观看一区| 欧美日韩在线观看一区二区 | 日本系列欧美系列| www.日日操| 国产在线精品不卡| 亚洲天堂2024| 欧美国产日韩精品免费观看| 91高清免费观看| 五月天亚洲精品| 日批视频免费观看| 91精品国产91综合久久蜜臀| 色婷婷综合视频| 在线看国产精品| а_天堂中文在线| 国产成人在线一区二区| 国产精品一区三区在线观看| 国产 高清 精品 在线 a| 尤物tv在线精品| 天天综合中文字幕| 国产日韩欧美一区在线| 一起操在线视频| 91网页版在线| 国产jizz18女人高潮| 一区二区三区视频在线看| 亚洲免费在线视频观看| 欧美一区二区精品在线| 免费黄色片在线观看| 欧美乱大交xxxxx另类电影| 欧美性猛交xxx高清大费中文| 欧日韩在线观看| 国产高清日韩| 鲁鲁视频www一区二区| 亚洲久久久久| 国产xxxxx在线观看| 国产精品一区一区三区| 国产精品高清无码在线观看| 亚洲自拍偷拍麻豆| 一级黄色大片免费| 日韩国产精品亚洲а∨天堂免| 香蕉视频免费在线看| 久热99视频在线观看| 女海盗2成人h版中文字幕| 91精品综合久久| 久久精品国产99久久| 国产最新免费视频| 国产91精品入口| 麻豆明星ai换脸视频| 色成人在线视频| 手机福利小视频在线播放| 九九热这里只有在线精品视| 精品美女一区| 日韩av电影免费观看| 模特精品在线| 日韩免费高清一区二区| 一区二区三区免费看视频| 亚洲中文字幕一区二区| 在线观看日韩av| 成人片免费看| 久久精品中文字幕一区二区三区 | 国产亚洲制服色| 日韩欧美高清在线观看| 日韩视频一区二区| а√天堂资源地址在线下载| 国产综合福利在线| 久久婷婷蜜乳一本欲蜜臀| 性刺激的欧美三级视频| 国产欧美中文在线| 五月天中文字幕| 国产一区二区免费| 中文另类视频| 五码日韩精品一区二区三区视频| 日本电影一区二区| 男女激情无遮挡| 99久久精品免费精品国产| 日韩欧美高清在线观看| 精品国精品自拍自在线| 青春草在线视频| 成人资源av| 影音先锋久久精品| 精品一区二区视频在线观看| 婷婷夜色潮精品综合在线| 亚洲 欧美 激情 另类| 2019最新中文字幕| 国产一区二区三区四区五区| 免费裸体美女网站| 国产色91在线| 一区二区三区免费观看视频| 日韩综合视频在线观看| 成人激情久久| www插插插无码视频网站| 91在线视频观看| 337p粉嫩色噜噜噜大肥臀| 中日韩美女免费视频网站在线观看| 美洲精品一卡2卡三卡4卡四卡| 国产99视频在线观看| 欧美亚洲精品在线| 天天综合成人网| 亚洲高清免费观看| 人成免费电影一二三区在线观看| 久久国产视频网站| av一级亚洲| 苍井空浴缸大战猛男120分钟| 国产电影精品久久禁18| 黄色小视频在线免费看| 亚洲片av在线| 国产不卡精品| 国产精品一线二线三线| 久久精品亚洲精品国产欧美| 一本久道久久综合无码中文| 欧美大尺度在线观看| 天海翼亚洲一区二区三区| 色婷婷一区二区三区av免费看| 久久天天做天天爱综合色| 在线视频你懂得| 欧美成人合集magnet| 日韩美脚连裤袜丝袜在线| 中文字幕亚洲乱码| 亚洲国产aⅴ成人精品无吗| 国产高清免费在线播放| 国产成人精品一区二区三区福利| 五月开心六月丁香综合色啪| 日本少妇xxxx| 欧美亚洲综合网| h片视频在线观看| 亚洲精品日韩成人| 风间由美一区二区三区在线观看| 中文字幕在线观看2018| 日韩电影免费在线观看中文字幕| av免费不卡| 在线天堂一区av电影| 99久久精品费精品国产一区二区| 精品在线视频观看|