Android JUnit测试中TracLogger类logFileOutputStream未初始化的问题解决求助
Android JUnit测试中TracLogger类logFileOutputStream未初始化的问题解决求助
哈喽,我来帮你分析下这个问题的根源,以及对应的解决办法:
首先,咱们得搞清楚为什么会出现lateinit property logFileOutputStream has not been initialized这个错误:
你的TracLogger在init块里尝试创建FileOutputStream,但如果这个过程抛出异常(比如mock的Context获取外部存储路径返回null、文件创建失败等),代码就会进入catch块,而logFileOutputStream作为lateinit变量,此时完全没被赋值。后续调用log()方法时,访问这个未初始化的变量就会触发错误。而且你当前的catch块只打印了Log,没有任何额外处理,导致外部完全感知不到初始化失败的情况。
下面是具体的解决步骤,分两部分优化:
一、修复TracLogger类本身的健壮性
- 把
lateinit var logFileOutputStream: FileOutputStream改成可空类型:var logFileOutputStream: FileOutputStream? = null,这样即使初始化失败,变量也有默认值null,不会触发未初始化异常,和你后续if(logFileOutputStream != null)的判断逻辑也能匹配上。 - (可选)如果希望初始化失败时能及时通知调用方,不要默默吞掉异常,可以在catch块里抛出一个自定义的初始化异常,比如:
catch (e: Exception) { val errorMsg = "writeLogToFile failed with error ${e.message}" Log.d(TAG, errorMsg) throw LoggerInitializationException(errorMsg, e) }
(需要自己定义LoggerInitializationException这个自定义异常类)
二、完善单元测试中的Mock逻辑
你的测试里只mock了Context和ITracLogInfo,但没有给关键方法指定返回值,导致文件路径计算失败、文件创建失败,进而logFileOutputStream初始化失败:
- Mock外部存储路径:给
context.getExternalFilesDir指定一个本地测试可用的临时目录,避免因为mock Context返回null导致路径异常:
@Before fun setup() { Mockito.mockStatic(Log::class.java) // 创建临时测试目录 val testDownloadDir = File(System.getProperty("java.io.tmpdir"), "test_downloads") testDownloadDir.mkdirs() // Mock Context的getExternalFilesDir方法 `when`(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)).thenReturn(testDownloadDir) // Mock ITracLogInfo的appName属性 `when`(iTracLogInfo.appName).thenReturn("TestApp") logger = TracLogger(iTracLogInfo, context) }
- 固定时间戳避免断言失败:你测试里用了
Date()生成当前时间,每次测试的时间不一样会导致断言失败,建议mockDate类或者用固定时间:
@Test fun testLog() { val message = "Test message" // 固定一个时间戳,确保断言的时间字符串一致 val fixedDate = Date(1717000000000) Mockito.mockStatic(Date::class.java).use { mockedDate -> mockedDate.`when` { Date() }.thenReturn(fixedDate) logger.log(message) // 读取文件内容并断言 val logFile = File(logger.logFolder + "/" + iTracLogInfo.appName + "log.txt") val fileContent = logFile.readText() val expectedContent = "${DateFormatterUtility.formatDateTimeToString(fixedDate, "MM/dd/yyyy HH:mm:ss.SSS")} : $message \n" assertEquals(expectedContent, fileContent) } }
- 清理测试文件:在
@After方法里删除测试生成的文件,避免影响后续测试:
@After fun tearDown() { val logFile = File(logger.logFolder + "/" + iTracLogInfo.appName + "log.txt") if (logFile.exists()) logFile.delete() val logsFolder = File(logger.logFolder) if (logsFolder.exists()) logsFolder.delete() val testDownloadDir = File(System.getProperty("java.io.tmpdir"), "test_downloads") if (testDownloadDir.exists()) testDownloadDir.delete() }
按照上面的步骤调整后,你的测试应该就能正常运行,不会再出现logFileOutputStream未初始化的问题啦。
备注:内容来源于stack exchange,提问作者Anshul Tyagi
相关产品推荐
相关产品推荐

