日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

记一次关于mock Systemc.currentTimeMillis的实践

發布時間:2024/4/11 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记一次关于mock Systemc.currentTimeMillis的实践 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

因為在寫單測過程中,發現@PrepareForTest和JaCoCo會有沖突,所以想要將JaCoCo修改為offline模式,但是這樣一來,就需要對utils等模塊全部重新寫單測。
從單測的角度來說各個模塊的單測各自獨立是比較推薦的,模塊A的單測就寫在模塊A里。但是很多工具類單獨寫單測也還是比較麻煩的,就想著是否有其他辦法可以繞過這個問題

介于我們項目中需要使用@PrepareForTest的場景幾乎都是用于mock系統時間戳(其他場景下用于第三方類并不影響我們項目覆蓋率的統計),由于使用@PrepareForTest會導致調用了系統時間戳的類無法統計覆蓋率,所以目前項目中有很多涉及到時間的數據構造都是通過采用在當前時間戳的基礎上加減小時數來做到的。這樣一來就會有幾個問題

  • 其實這樣單測的可讀性不好
  • 對于一些涉及到時間的斷言在寫的時候也是通過調用函數獲取預期值,和單測的目的也相違背
  • 就想到針對我們項目的這種情形,是否可以不使用JaCoCo的離線模式,而采用其他辦法在測試類中mock系統時間戳

    封裝工具類,替換掉Systemc.currentTimeMillis()

    最簡單的辦法就是將System.currentTimeMillis()封裝成一個靜態工具類,把所有調用系統時間戳的地方都改成調用該方法,這樣在使用PowerMock的時候就不用擔心系統時間戳的調用類無法統計到覆蓋率

    public class SystemUtils {public static Long currentTimeMillis(){return System.currentTimeMillis();} } //原來的public static boolean isBeforeTime(long beginTimeUTC, long offset) {long timeNow = System.currentTimeMillis();if (beginTimeUTC - timeNow > THREE_DAYS) {return true;} return false;}//修改后public static boolean isBeforeTime(long beginTimeUTC, long offset) {long timeNow = SystemUtils.currentTimeMillis();if (beginTimeUTC - timeNow > THREE_DAYS) {return true;} return false;}

    使用其他時間戳api

    java 8 提供了新的關于日期操作的api, 相比以前的api更加易用和安全,推薦使用java 8的api替換上述獲取系統時間戳的方法。 比方說下面的LocalDateTime,我們可以通過 Clock.fixed在寫單測的時候將系統時間設置成任何你想要的值,或者直接mockLocalDateTime.now返回的時間結果也是可以的

    private static Clock clock = Clock.systemDefaultZone();private static ZoneId zoneId = ZoneId.systemDefault();public static Long getSystemTime(){return LocalDateTime.now(clock).atZone(zoneId).toInstant().toEpochMilli();}//設置當前系統時間為指定的LocalDateTimepublic static void useFixedClockAt(LocalDateTime date) {clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId);}//恢復當前系統時間public static void useSystemDefaultZoneClock() {clock = Clock.systemDefaultZone();}

    使用AspectJ代理

    我只是想要將系統時間戳的方法調用結果進行修改,那么是否可以使用代理來實現呢?
    根據參考資料,我先嘗試了使用AspectJ來實現對Systemc.currentTimeMillis()方法的代理

    public aspect ChangeSystemTimeMillis {long around(): call(* java.lang.System.currentTimeMillis()){return TimeMachine.getSystemTimestamp();} } public class TimeMachine {public static Long systemTimestamp = 0L ;public static Long getSystemTimestamp() {return systemTimestamp;}public static void setSystemTimestamp(String datetime) throws ParseException {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = simpleDateFormat.parse(datetime);TimeMachine.systemTimestamp = date.getTime();}public static void setSystemTimestamp(Long systemTimestamp) {TimeMachine.systemTimestamp = systemTimestamp;}}

    這樣,我們就可以通過setSystemTimestamp方法設置系統時間戳的返回值,默認返回0

    但是在驗證過程中發現一個問題:
    我只是想要在測試代碼里對系統時間戳的調用進行代理,在測試或者生產環境真正調用代碼的時候不需要這個代理操作,在網上查了下資料發現可以通過aspectj-maven-plugin插件實現 , 配置如下

    <plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.10</version><configuration><showWeaveInfo>true</showWeaveInfo><source>1.8</source><complianceLevel>1.8</complianceLevel><target>1.8</target></configuration><executions><execution><!--該織入在test-compile階段執行,需要先通過maven執行該過程才可以得到代理class--><id>test-compile</id><configuration><!--在執行測試編譯的時候會對源代碼做織入生成新的class文件--><weaveMainSourceFolder>true</weaveMainSourceFolder></configuration><goals><goal>test-compile</goal></goals></execution></executions></plugin>

    這樣做,在執行mvn相關命令的是(test-compile,package),可以在test-classes下看到生成的被織入的class文件
    (但是沒有事先通過maven編譯是無法生成對應的代理class,也就無法起到修改系統時間戳的目的)

    織入成功后的class

    private boolean isOverdue(Long beginTime, Double timeZone) {return (double)(beginTime + 28800000L) - timeZone * 3600.0D * 1000.0D + (double)OVERDUE_TIME < (double)currentTimeMillis_aroundBody1$advice(this, ChangeSystemTimeMillis.aspectOf(), (AroundClosure)null);}

    本來以為這樣就成功了,但是在提交執行單測的時候又發現了另一個問題
    由于JaCoCo需要通過修改字節碼文件加入統計代碼類統計覆蓋率,而上述aspectj-maven-plugin在編譯時在test-classes下生成了新的class文件,這里是不包含統計代碼的,所以哪怕我的單測都通過了,原來的代碼也沒有被JaCoCo統計到覆蓋率

    這就跟一開始的目的相違背了,所以最后還是采用了離線JaCoCo模式來解決這個問題。

    記錄一下這次探索,我看到StackOverFlow有人建議使用LTW,不過我沒嘗試成功,那個對系統類好像并不有效,如果有人解決了這個問題歡迎一起分享下

    參考資料:

    Overriding System Time for Testing in Java

    總結

    以上是生活随笔為你收集整理的记一次关于mock Systemc.currentTimeMillis的实践的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。