这篇会讲解怎麽直接用 jUnit 来测试 parser 和 Android 环境的 parser ,接续上一篇,我们现在已经准备好了 RSS feed 的测试案例和 XML 档案,我们要想办法去取得 XML 的档案内容。我们可以把读取档案内容放在一个 util class 里面,这个 util 我们就放在一个 :testCommon
的 module 里,方便我们之後在任何一个 module 底下做测试。
object XmlFileReader {
fun readFile(filename: String): String {
val stringBuilder = StringBuilder()
this::class.java.classLoader?.getResourceAsStream(filename)?.use { inputStream ->
var availableCount = inputStream.available()
while (availableCount > 0) {
val string = inputStream.readByteString(availableCount).string(Charsets.UTF_8)
stringBuilder.append(string)
availableCount = inputStream.available()
}
}
return stringBuilder.toString()
}
}
用法就是呼叫 XmlFileReader.readFile
後面接完整路径的档名就可以了!实作部分主要是把档案透过 inputStream
的方式一段段读出放在 StringBuilder
里,当档案读完後就把 StringBuilder
的内容转成一般的字串。
拿到 XML 档案内容後,我们就可以来写测试了!要测试一个 parser ,其中的测项包含很多个 case ,但每个测试项目的程序码都是:
@Test
fun parse() {
val xml = XmlFileReader.readFile(rssFilePath)
val actualChannel = TestRssDataParser.parse(xml)
actualChannel shouldBe expectedChannel
}
infix fun Any?.shouldBe(expected: Any?) = Assert.assertEquals(expected, this)
假设我们对这个 TestRssDataParser
有 30 几个测项,我们是不是就要写 30 几个这种 test function ?其实不用,我们可以使用 jUnit 的参数化测试,只要我们把测试项目的输入变数参数化,再验证测试的输出就可以了,不用写 30 几个 test function ,这是一个很方便的功能,因为很多时候在写测试的时候,都是输入不同,但是测试的流程是差不多的,这时候参数化测试的帮助就很大。
class CustomParserLocalTest {
@RunWith(Parameterized::class)
class CustomParserParseFunctionTest(
private val rssFilePath: String,
private val expectedChannel: TestRssData?
) {
companion object {
@JvmStatic
@Parameterized.Parameters
fun getTestingData() = listOf(
arrayOf("${RSS_FOLDER}/rss_v2_full.xml", TestData.RSS_DATA),
arrayOf("${RSS_FOLDER}/rss_v2_has_non_channel_attrs.xml", TestData.RSS_DATA),
arrayOf("${RSS_FOLDER}/rss_v2_has_non_channel_attrs_follow_behind.xml", TestData.RSS_DATA),
arrayOf("${RSS_FOLDER}/rss_v2_has_non_item_attrs.xml", TestData.RSS_DATA),
arrayOf("${RSS_FOLDER}/rss_v2_has_non_item_attrs_follow_behind.xml", TestData.RSS_DATA),
)
}
@Test
fun parse() {
val xml = XmlFileReader.readFile(rssFilePath)
val actualChannel = TestRssDataParser.parse(xml)
actualChannel shouldBe expectedChannel
}
}
}
在写参数化测试的时候,要在 class 的前面使用 annotation 标注 @RunWith(Parameterized::class)
,jUnit 就会知道接下来要进行参数化测试。这个类别有两个输入的参数 rssFilePath
和 expectedChannel
, rssFilePath
为 模拟 RSS feed 的测试案例 XML , expectedChannel
则为该测项的预估结果,若测试的结果不等於 expectedChannel
,则该测试失败。在 getTestingData
回传的列表是一组组的测试参数,也就是该测项的 XML 档案和预测结果,分别对应到 rssFilePath
和 expectedChannel
,而下面的 parse function 是每个测项的测试流程。
在 Android 的 instrumental 测试,其实也是类似的参数化测试方式,只是测试本身是跑在 Android 的装置上面,而不是跑在电脑的 JVM 上,因为 Android 的 parser 有用到那些 Android 相关的 dependency ,例如 XmlPullParser ,所以才会需要跑在 Android 的实机上。以下是 Android instrumental test 的范例程序码:
@RunWith(Enclosed::class)
class AndroidITunesParserTest {
@RunWith(Parameterized::class)
class ITunesParserParseFunctionTest(
private val rssFilePath: String,
private val expectedChannel: ITunesChannelData
) {
companion object {
@JvmStatic
@Parameterized.Parameters
fun getTestingData() =listOf(
arrayOf("${ITUNES_FOLDER}/itunes_rss_v2_full.xml",FULL_ITUNES_CHANNEL),
arrayOf("${ITUNES_FOLDER}/itunes_rss_v2_some_channel_attrs_missing.xml",PARTIAL_ITUNES_CHANNEL),
arrayOf("${ITUNES_FOLDER}/itunes_rss_v2_without_itunes_attributes.xml",PARTIAL_ITUNES_CHANNEL_2),
)
}
private val parser: AndroidITunesParser = AndroidITunesParser()
@Test
fun parse() {
val xml = XmlFileReader.readFile(rssFilePath)
val actualChannel = parser.parse(xml)
actualChannelshouldBeexpectedChannel
}
}
@RunWith(Parameterized::class)
class ITunesErrorTagParserErrorTagTest(private val rssFilePath: String): ErrorTagParserBaseTest() {
@Test(expected = XmlPullParserException::class)
fun parse() {
val parser = AndroidITunesParser()
val xml = XmlFileReader.readFile(rssFilePath)
parser.parse(xml)
}
}
}
测试 Parser 虽然不难,但要把测试整理的很好,则需要花一些工夫。我觉得在写类似的测试时,有两个重点:
:testCommon
module 。
所有的安排都不一定会照着计画走 比如说以前的旅行可能会像是踩点一样 安排好很多个景点 在有限时间底...
心得 哈罗大家,今天是铁人挑战第三十天,终於来到最後一天了,老实说我真的没想过我会参加这个比赛,更没...
前言 当我们终於准备上架 Google Play,我们需要决定在哪些国家、年龄层、装置等才能够看到我...
118. Pascal's Triangle 今天要挑战的是实作一个在数学上有许多应用的帕斯卡三角形...
您是 VMware 认证技术助理 - 数据中心虚拟化考试的有抱负的候选人之一吗?然後你就中了头奖!多...