【问题标题】:Java utils class, static methods vs injecting the utils classJava utils 类,静态方法与注入 utils 类
【发布时间】:2020-03-13 05:38:24
【问题描述】:

你们如何创建实用程序类?有标准方法吗?

就像标题说的那样,你可以有这样的东西:

public class Utils {

   public static method1(){...}

   public static method2(){...}
...
}

并通过调用Utils.method1() 来使用它,但这样一来,当您为使用此 utils 类的类编写单元测试时,您无法模拟静态方法,因此如果它们有错误,单元测试将失败。

或者,您可以使用这些 utils 在类的构造函数中提供 utils 类的实例,这样您就可以在单元测试中模拟它,但对我来说,将 utils 类的实例提供给每个人看起来非常尴尬使用它的类,并且通常必须创建 utils 类的实例。 我的意思是,如果我们有使用 Utils 类中的方法的 A 类,我们可以这样做:A a = new A(new Utils());

有没有一种方法可以同时实现?或者至少是行业标准的东西?还是我没有想到的其他方式?

【问题讨论】:

  • 第二种方法是什么意思(“将utils类注入​​到构造函数中使用它的类中……但看起来很尴尬”)?
  • 已编辑,希望现在更清楚
  • 您可以将方法保持为静态,但使用 statick mocking 在使用 Utils 类的代码测试中使用类似 power mock 的东西对它们进行存根
  • commons.apache.org/proper/commons-lang/apidocs/org/apache/… Apache StringUtils 使用静态方法,我猜他们知道自己在做什么
  • @Bentaye 就像我提到的那样,这种方式在单元测试时有一个缺陷,我不确定他们在编写这个 utils 类时是否考虑到了这一点,因为他们真的不能...... @ErnestKiwele 我不知道一种方法模拟静态方法或对静态方法的调用,我的意思是您将如何将您的代码进行的调用 Utils.method1() 重定向到其他一些模拟实现?

标签: java oop


【解决方案1】:

实用程序类应该是 API 的一部分并经过良好测试。如果你开始考虑依赖注入和在那个层面上模拟,你就已经输了。模拟应该非常小心。

替代方案:

  • 默认接口方法实现(Java 8 起)
  • 修饰类实例并提供实用功能的适配器。

【讨论】:

    【解决方案2】:

    通常,您可以(也不必)为实用方法编写静态方法,而无需模拟或切换到它们的不同实现。
    某些处理可能不需要模拟或实现切换。所以让它们成为静态实用方法是可以接受的。
    以数学函数为例,例如计算数字的平方根。您不需要模拟它或切换到另一个实现。
    所以使用静态方法应该不会引起任何问题。

    对于您不知道是否需要模拟/切换到其他实现的情况,我认为您应该更喜欢实例方法,因为它更灵活。

    【讨论】:

    • 这不是知道是否需要使用模拟的问题,我试图描述一种情况,当您编写一些新类以及这些类使用的新 utils 类时,就像任何需要测试 utils 类的新代码,因此当您为使用它的类编写单元测试时假设它可以工作(这是您以静态方式从该类调用方法时必须假设的)似乎有点我错了
    【解决方案3】:

    您可以在使用 Utils 类的类的测试中模拟静态方法。假设你使用 JUnit,你可以添加对 powermock 的依赖:

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>1.7.4</version>
    </dependency>
    

    假设一个客户端类,如:

    class ClientCode {
        public void doSomething() {
            String value = Utils.method1();
        }
    }
    

    在ClientCode的测试中,可以使用powermock:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(Utils.class)
    public class ClientCodeTest {
    
        @Test
        public void testDoSomething() {
            PowerMockito.mockStatic(Utils.class);
            BDDMockito.given(Utils.method1()).willReturn("<mock string value>");
        }
    }
    

    【讨论】:

    • 你应该提到PowerMock利用字节码操作。
    • 非常有趣的答案!谢谢!为什么这有关系? @图灵85
    • 因为它会影响其他工具,例如 JaCoCo/EclEmma(代码覆盖工具)。
    • 我明白了(你之前提到的时候不明白),谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    • 1970-01-01
    • 2011-01-17
    • 1970-01-01
    • 2016-06-14
    • 2021-04-27
    • 1970-01-01
    相关资源
    最近更新 更多