tdd实现四则运算_如何使用TDD在Android中实现您的第一个自定义棉绒规则(第1部分)

tdd实现四则运算

In this article I will demonstrate how to implement your first custom lint check, while using TDD. This will be the first post of a series about this not so common subject.

在本文中,我将演示如何在使用TDD时实现您的第一个自定义棉绒检查。 这将是关于这个不太常见的主题的系列文章的第一篇。

定制皮棉检查 (Custom Lint Check)

Android comes with a set of lint checks, which can be augmented with custom ones. I could not find any good and updated official documentation explaining how to do this, but fortunately there are some great articles and examples in the community ([1][2][3][4][5]). I will just give an overview of the bare minimum for this article, so I recommend you to read one of the mentioned articles in order to get a better understanding of how they work.

Android附带了一组皮棉检查 ,可以添加自定义检查 。 我找不到任何好的和更新的官方文档来说明如何执行此操作,但是幸运的是,社区中有一些很棒的文章和示例( [1] [2] [3] [4] [5] )。 我将仅概述本文的最低要求,因此,建议您阅读其中一篇文章,以更好地理解它们的工作方式。

The basic pieces to build a lint check are:

建立皮棉检查的基本内容是:

  • Detector: it is how you traverse the code to report issues

    检测器 :这是遍历代码以报告问题的方式

  • Issue: it is what will be show when the Detector finds an error with your code. They can have different severities, priorities and categories

    问题 :检测器发现您的代码错误时将显示该内容。 他们可以具有不同的严重程度,优先级和类别

  • Implementation: where you configure your Detector and what set of files it will handle (e.g. Java source code, XML files,…)

    实施 :在何处配置检测器以及它将处理的文件集(例如Java源代码,XML文件等)

  • Registry: contains a list of all the Issues it can run. The BuiltinIssueRegistry contains the default ones.

    注册表:包含它可以运行的所有问题的列表。 BuiltinIssueRegistry包含默认值。

检测方法是否声明了5个以上的参数 (Detect if a method declares more than 5 parameters)

For our first custom lint check, we want to add a check for us to be warned whenever we have declared a method with more than 5 parameters. This can be useful in order to keep our methods short and intelligible at first glance, so the reader doesn’t have to keep context of multiple parameters when looking at a method.

对于我们的第一个自定义棉绒检查,我们想添加一个检查,以便在声明具有5个以上参数的方法时向我们发出警告。 乍看之下,这对于使我们的方法简短易懂很有用,因此读者在查看方法时不必保持多个参数的上下文

So let’s start. We are going to try following TDD practices while implementing this check, so the first thing would be to write a unit test. For lint unit tests, there is a handy class which does the heavy lifting in setting up what we need, so we extend from it: LintDetectorTest.

因此,让我们开始吧。 在实施此检查时,我们将尝试遵循TDD做法,因此第一件事就是编写单元测试。 对于皮棉单元测试,有一个方便的类在设置所需的内容时进行了繁重的工作,因此我们从它进行了扩展: LintDetectorTest

class TooManyParametersDetectorTest : LintDetectorTest() {


    override fun getDetector(): Detector = TODO()


    override fun getIssues(): MutableList<Issue> = TODO()


}

There are two methods which we need to override: one to declare which Detector we are testing and other to list all the Issues under testing. As we don’t have a Detector class yet, we need to create it and declare the single Issue we are going to try to detect and subsequently report.

我们需要重写两种方法:一种方法声明我们正在测试的检测器,另一种方法列出所有正在测试的问题。 由于我们还没有Detector类,我们需要创建它并声明我们要尝试检测并随后报告的单个Issue。

You can see that we are creating and configuring our issue with the message we are going to show, and setting the severity as a warning. Furthermore, we need to create an Implementation and declare that we are interested in Java and Kotlin source code files (scope). Finally, we will add an utility method so we can report that we have detected this warning in a specific location.

您可以看到我们正在使用要显示的消息创建和配置问题,并将严重性设置为警告。 此外,我们需要创建一个Implementation并声明我们对Java和Kotlin源代码文件(作用域)感兴趣。 最后,我们将添加一个实用程序方法,以便可以报告已在特定位置检测到此警告。

class TooManyParametersDetector : Detector(), SourceCodeScanner {


    private fun reportUsage(context: JavaContext, location: Location) {
        context.report(
            issue = ISSUE,
            location = location,
            message = "Method should not declare more than 5 parameters"
        )
    }


    companion object {
        private val IMPLEMENTATION = Implementation(
            TooManyParametersDetector::class.java,
            Scope.JAVA_FILE_SCOPE
        )


        val ISSUE: Issue = Issue.create(
            id = "TooManyParametersDetector",
            briefDescription = "Method should not declare more than 5 parameters",
            explanation = """
                    You should limit the number of parameters you method receive, 
                    in order to make your method more legible and easier to use correctly.
                """.trimIndent(),
            category = Category.CORRECTNESS,
            priority = 5,
            severity = Severity.WARNING,
            androidSpecific = true,
            implementation = IMPLEMENTATION
        )
    }


}

Now that we have our Detector and associated Issue, we can fill the TODOs we left in the test file. We will also add our first unit test, which will guarantee that lint does not report errors for a class with a parameter-less method.

现在我们有了检测器和相关的问题,我们可以填充在测试文件中剩下的TODO。 我们还将添加我们的第一个单元测试,这将确保lint不使用无参数方法报告类的错误。

Running this unit test, it should pass, as there is nothing in our Detector yet, and there is nothing to detect here. We can go ahead and create other unit tests for cases where we should not report warnings: methods with 1 to 5 parameters, both in Java and Kotlin. These all should pass successfully. It is important to have this baseline of unit tests, so we can make sure we do not break them later.

运行此单元测试,它应该通过,因为我们的检测器中还没有任何东西,因此这里没有东西可检测。 对于不应该报告警告的情况,我们可以继续创建其他单元测试:Java和Kotlin中带有1到5个参数的方法。 这些都应该成功通过。 拥有单元测试的基准很重要,因此我们可以确保以后不要破坏它们。

override fun getDetector(): Detector = TooManyParametersDetector()


override fun getIssues(): MutableList<Issue> = mutableListOf(TooManyParametersDetector.ISSUE)


@Test
fun `java method with 0 parameters`() {
    val javaFile = java(
        """
        package com.brokoli.lint;

        class MyClass {

            public void methodWith0Parameters() {

            }

        }
    """
    ).indented()


    val lintResult = lint()
        .files(javaFile)
        .run()


    lintResult.expectClean()
}

Now it is time to create our unit test with a method declaring 6 parameters, which should trigger a warning. Running this test should fail, so now we can go back to our Detector class to actually implement the required logic.

现在该使用声明6个参数的方法来创建我们的单元测试了,这将触发警告。 运行该测试应该会失败,因此现在我们可以返回到Detector类,以实际实现所需的逻辑。

@Test
fun `kotlin method with 6 parameters`() {
    val kotlinFile = kotlin(
        """
        package com.brokoli.lint;

        class MyClass {

            fun methodWith6Parameters(first: Boolean, second: String, third: Int, fourth: Long, fifth: Char, sixth: Boolean) {

            }

        }
    """
    ).indented()


    val lintResult = lint()
        .files(kotlinFile)
        .run()


    lintResult
        .expectWarningCount(1)
        .expect(
            """
            src/com/brokoli/lint/MyClass.kt:5: Warning: Method should not declare more than 5 parameters [TooManyParametersDetector]
                fun methodWith6Parameters(first: Boolean, second: String, third: Int, fourth: Long, fifth: Char, sixth: Boolean) {
                ^
            0 errors, 1 warnings
            """.trimIndent()
        )
}

How can we identify if a method declares more than 5 parameters? It turns out this is quite easy using our Detector class.

我们如何确定一个方法声明的参数是否超过5个? 事实证明,使用我们的Detector类非常简单。

But first, let’s look at the parsed tree for this Kotlin file we are creating in our unit test. You can generate this by calling “asRecursiveLogString()” in a given UElement. Note that what we want is to get a reference for the UAnnotationMethod and check how many parameters it contains.

但是首先,让我们看一下我们在单元测试中创建的Kotlin文件的解析树。 您可以通过在给定的UElement中调用“ asRecursiveLogString ()”来生成此代码。 请注意,我们想要获取UAnnotationMethod的引用并检查其包含多少参数。

UFile (package = com.brokoli.lint)
    UClass (name = MyClass)
        UAnnotationMethod (name = methodWith6Parameters)
            UParameter (name = first)
                UAnnotation (fqName = org.jetbrains.annotations.NotNull)
            UParameter (name = second)
                UAnnotation (fqName = org.jetbrains.annotations.NotNull)
            UParameter (name = third)
                UAnnotation (fqName = org.jetbrains.annotations.NotNull)
            UParameter (name = fourth)
                UAnnotation (fqName = org.jetbrains.annotations.NotNull)
            UParameter (name = fifth)
                UAnnotation (fqName = org.jetbrains.annotations.NotNull)
            UParameter (name = sixth)
                UAnnotation (fqName = org.jetbrains.annotations.NotNull)
            UBlockExpression
        UAnnotationMethod (name = MyClass)

In order to do this we need to declare we are interested only in method elements. This is done by overriding the getApplicableUastTypes() function, and returning the UMethod class. Then, we need to provide an UElementHandler, which contains a set of functions we can override to be notified of specific constructions while parsing our source code. Again, as we are interested only in methods, we override the visitMethod() function which receives the corresponding UMethod instance. Having that, we can check if the number of parameters is greater than our magic number, 5. If it is, we can report its usage, which will actually trigger the lint warning.

为此,我们需要声明我们仅对方法元素感兴趣。 这是通过重写getApplicableUastTypes()函数并返回UMethod类来完成的。 然后,我们需要提供一个UElementHandler,其中包含一组函数,在解析源代码时,可以重写这些函数以通知特定的构造。 同样,因为我们只对方法感兴趣,所以我们重写了visitMethod()函数,该函数接收相应的UMethod实例。 有了它,我们可以检查参数的数量是否大于魔术数5。如果是,我们可以报告其使用情况,这实际上会触发皮棉警告。

override fun getApplicableUastTypes(): List<Class<out UElement>>? {
    return listOf(UMethod::class.java)
}


override fun createUastHandler(context: JavaContext): UElementHandler? {
    return MethodHandler(context)
}


inner class MethodHandler(private val context: JavaContext) : UElementHandler() {
  
    val MAX_NUMBER_OF_METHOD_PARAMETERS = 5


    override fun visitMethod(node: UMethod) {
        if(node.parameters.size > MAX_NUMBER_OF_METHOD_PARAMETERS) {
            reportUsage(context, context.getLocation(node))
        }
    }


}

结论 (Conclusion)

And that’s it! We have implemented our first custom lint check. You can find the complete code here and the tests here. In the repository you can see other more complex custom lint rules, which I will describe in the next articles.

就是这样! 我们已经实现了第一个自定义皮棉检查。 您可以在此处找到完整的代码并在此处找到测试。 在存储库中,您可以看到其他更复杂的自定义皮棉规则,我将在下一篇文章中对其进行描述。

This article is part of a series about creating custom lint rules in Android:Part 1: How to implement your first custom lint rule in Android using TDDPart 2: How to implement a custom lint rule in Android that requires an overall view of the projectPart 3: How to implement a custom lint rule in Android to warn against checked exception thrown from Kotlin Part 4: How to implement a custom lint rule in Android to handle differences in Exception handling between Java and KotlinPart 5: How to implement a custom lint rule in Android to detect if we are setting the fragment manager before calling Activity onCreate methodPart 6: (Maybe) How to implement a custom lint rule in Android to detect if we are passing an immutable collection to a Java method which needs a mutable one

本文是有关在Android中创建自定义棉绒规则的系列文章的一部分: 第1部分:如何使用TDD在Android中实现您的第一个自定义棉绒规则 第2部分:如何在需要项目总体视图的Android中实现自定义棉绒规则第3部分:如何在Android中实现自定义棉绒规则以警告Kotlin引发的已检查异常第4部分:如何在Android中实现自定义棉绒规则以处理Java和Kotlin之间的异常处理差异第5部分:如何实现自定义棉绒Android中的规则以检测是否在调用Activity onCreate方法之前设置了片段管理器第6部分:( 也许 )如何在Android中实现自定义的lint规则以检测我们是否将不可变的集合传递给需要可变变量的Java方法

翻译自: https://medium.com/swlh/how-to-implement-your-first-custom-lint-rule-in-android-using-tdd-part-1-d3c9a58a7aa8

tdd实现四则运算

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值