V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
williamfzc
V2EX  ›  程序员

一个适用于 android/jvm 的冒烟单测生成器 randunit

  •  3
     
  •   williamfzc · 2021-03-31 10:30:35 +08:00 · 845 次点击
    这是一个创建于 1141 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    在持续交付越来越流行的今天,单测作为保障 CI 质量的重要一环也开始在国内被重视起来。

    不过在单测上大家的态度还是比较矛盾的,担心的事情主要有两个:

    • 从 0 到 1 的第一步不知道从何下手
    • 万一花大力气做了之后发现没什么用怎么办

    但是缺少这一环,在整个 devops 流程中很多编译时严重问题会被延缓到运行时暴露,这对于项目效率阻碍也不小。。

    于是就有了灵感来源:

    • 自动生成一系列冒烟级别单测用例,并能发现严重问题
    • 接入成本低,能无痛与现有流程结合
    • 能对 android 生效(我司重移动端

    做了什么

    RandUnit 取义自 Random UnitTest,他会:

    • 根据提供的包名或入口类,搜索所有相关的待测试类与方法
    • 根据搜索结果,为每个方法生成一系列 statements 用于测试
    • 像常规单测流程一般,在 junit 上运行这些 statements,得到测试结果

    而这一切只需要一次简单的复制粘贴:

    import com.williamfzc.randunit.env.NormalTestEnv
    import com.williamfzc.randunit.models.StatementModel
    import com.williamfzc.randunit.scanner.ScannerConfig
    import org.junit.Test
    import org.junit.runner.RunWith
    import org.junit.runners.Parameterized
    
    @RunWith(Parameterized::class)
    class MinExampleTest(private val statementModel: StatementModel) {
        companion object {
            private val testEnv = NormalTestEnv()
            private const val packageName = "com.your.package"
            private val cases by lazy {
                val scannerConfig = ScannerConfig()
                scannerConfig.includeFilter.add(packageName)
    
                RandUnit.collectStatementsWithPackage(packageName, scannerConfig)
            }
    
            @JvmStatic
            @Parameterized.Parameters(name = "{0}")
            fun data(): Collection<StatementModel> {
                return cases
            }
        }
    
        @Test
        fun runStatements() {
            testEnv.runStatementInSandbox(statementModel)
        }
    }
    

    由于它是合法的 junit 用例,所以你可以在 ide 里直接运行它。直接 run with coverage 的话:

    ide.jpg

    可以看到,它帮你生成了 500+条用例并执行了。

    解决了啥

    再回头看看是不是解决了上面的三个问题:

    • 自动生成:目前的策略是在每次编译后自动搜索生成一系列 junit 用例并执行,有代码变更也无需改用例
    • 接入成本低:一次粘贴即可接入。除此之外,因为他是合法 junit 用例,那自然也可以像正常使用 junit 用例一样用它,例如在 CI 环境里
    • 对 android 生效:得益于 robolectric 的支持, randunit 能够很好地被应用到 android 项目中。不过上面的代码需要有微调,感兴趣可以看看项目主页

    像这种问题:

    override fun getCastOptions(context: Context?): CastOptions? {
    
        // oh, you import a non-existed class here!
        // it should cause a ClassNotFoundException
        Class.forName("import unknown class here!")
    
        ...
    }
    

    就不会被遗漏到集成之后啦:

    WARNING: error happened inside sandbox: java.lang.reflect.InvocationTargetException
    
    java.lang.ClassNotFoundException: import unknown class here!
    
    	at org.robolectric.internal.bytecode.SandboxClassLoader.getByteCode(SandboxClassLoader.java:158)
    

    链接

    1 条回复    2021-03-31 22:51:58 +08:00
    hantsy
        1
    hantsy  
       2021-03-31 22:51:58 +08:00   ❤️ 1
    这个不错,和国内满大街的 UI 换肤开源项目比,这算是真正有点价值的开源项目。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1020 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:44 · PVG 03:44 · LAX 12:44 · JFK 15:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.