繁体   English   中英

我们应该避免在java代码中编写静态方法以获得更好的可测试性吗?

[英]Shall we avoid writing static methods in our java code for better testability?

我更喜欢在我的java代码中使用静态方法,因为我认为它们是“功能性的” “无状态”并且副作用较小。 所以可能有一些辅助类和方法如下:

public class MyHelper {
    public static Set<String> array2set(String[] items) { ... }
    public static List<String> array2list(String[] items) { ...}
    public static String getContentOfUrl(String url) {
        // visit the url, and return the content of response
    }
}

public class MyApp {
    public void doSomething() {
        String[] myarray = new String[]{ "aa","bb"};
        Set<String> set = MyHelper.array2set(myarray);
        String content = MyHelper.getContentOfUrl("http://google.com");
    }
}

但是我的朋友说我们应该避免定义这样的静态实用程序方法,因为我们直接在我们的代码中调用它们,如果它们具有外部依赖性,则很难模拟它们或测试它们。 他认为代码应该是:

public class ArrayHelper {
    public Set<String> array2set(String[] items) { ... }
    public List<String> array2list(String[] items) { ...}
}
public class UrlHelper {
    public String getContentOfUrl(String url) {
        // visit the url, and return the content of response
    }
}

public class MyApp {
    private final ArrayHelper arrayHelper;
    private final UrlHelper urlHelper;
    public MyApp(ArrayHelper arrayHelper, UrlHelper urlHelper) {
        this.arrayHelper = arrayHelper;
        this.urlHelper = urlHelper;
    }
    public void doSomething() {
        String[] myarray = new String[]{ "aa","bb"};
        Set<String> set = arrayHelper.array2set(myarray);
        String content = urlHelper.getContentOfUrl("http://google.com");
    }
}

这样,如果我们想为MyApp编写单元测试,我们就可以模拟ArrayHelperUrlHelper并将它们传递给MyApp的构造函数。

我完全同意他的意见中的UrlHelper部分,因为原始静态代码使得MyApp不可测试。

但我对ArrayHelper部分有点困惑,因为它不依赖于任何外部资源,逻辑非常简单。 在这种情况下我们应该避免使用静态方法吗?

什么时候使用静态方法? 或者只是尽量避免使用它?


更新:

我们在开发中使用“TDD”,因此课程的可测试性通常是我们最关心的问题。

我只是在第一句中用“无状态”替换“功能性”这个词,因为那是真实的意思。

您可能永远不会想要模拟将数组转换为列表(或集合)的方法,并且此方法不需要任何状态且不依赖于任何环境,因此静态方法对我来说很好。

就像标准的Arrays.asList() (您应该使用它)。

另一方面,访问外部URL通常是您希望能够轻松模拟的东西,因为不会嘲笑它

  • 使测试成为集成测试
  • 要求在每次运行测试时都使用此外部URL,这可能无法保证
  • 要求让此外部URL返回您希望它在测试中返回的内容(如果您要测试错误事件,则包括错误)。

请注意Java专家中常见的一种疾病: 过度工程

在您的具体的例子,你要么没有 mockability问题。 如果您遇到问题,则不会提出一般性问题,因此我认为您目前没有问题。

一般的论点是static方法更简单,因此只要有选择,首选的选择。 一个可能的实例方法必须首先证明自己需要是一个实例方法。

如果这是我的项目,我会将任何改造推迟到实例方法,直到需要它变得清晰和存在的那一刻。

静态意味着您可以在不实例化类的情况下调用该方法。 如果你想将你的代码打包成一个类,并且你有一个只做一些逻辑或基本功能的函数,这很好。

只是不要使用静态函数来尝试和编辑类中的成员变量(显然)。

我个人认为使用静态函数很好,因为它是无状态的。

应该通过回答“这个方法是特定实例的功能吗?”这个问题来使用静态方法

你不应该根据测试来决定static方法,你应该根据设计来做。 您的示例不需要实例,因为它没有意义。 所以static是更好的选择。 您始终可以将这些方法包装在特定的测试器类中以进行测试。

自包含功能不是静态的唯一情况就是当您想要提供多个实现时,因为您需要继承而不得不避免static

我经常使用静态方法:

  • for factory方法(显式命名的构造函数)
  • 在面向对象的层上方提供功能层,以组成对象
  • 有时用于通用功能(Apache Commons有很多很好的例子)

我从不使用“单例”(静态对象)和引用静态对象的方法,因为它们是测试和重用的完全头痛。 我还避免将任何东西硬编码到可能需要更改的静态方法中。 有时我会提供多种方法 - 一种方法将所有依赖项作为参数,另一种方法使用较少的参数,使用一些默认(硬编码)值调用更灵活的方法。

java.lang.Math是静态的,这是一个很好的例子。 我认为静力学并没有收集垃圾,如果可能应该避免。

没有。

正如Peter Lawrey在该问题的评论中所提到的,Java就是面向对象编程。 虽然某些功能方面是可行的并且被放入例如。 Java 8,其核心Java不起作用。 static打破了学习如何做现代Java的好处 - 更不用说各种不那么有趣的范围问题了 - 没有任何目的可以使用它们, 除非你是某种真正的Java向导知道当你使用那个神奇的关键词会发生什么。

你不是巫师。 Java不起作用。 如果你想成为一名巫师,你可以学习。 如果您想以功能性方式进行编程,请查看Scala或Groovy等混合语言,或者探索功能齐全的世界,例如: Clojure的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM