在Java中模拟静态块 [英] Mocking Static Blocks in Java

查看:151
本文介绍了在Java中模拟静态块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Java的座右铭是仅仅因为Java有静态块,它并不意味着你应该使用它们。除了笑话之外,Java中有很多技巧会让测试成为一场噩梦。我最讨厌的两个是匿名类和静态块。我们有很多使用静态块的遗留代码,这些是我们编写单元测试的烦恼之一。我们的目标是能够为依赖于此静态初始化的类编写单元测试,并且代码更改最少。

My motto for Java is "just because Java has static blocks, it doesn't mean that you should be using them." Jokes aside, there are a lot of tricks in Java that make testing a nightmare. Two of the most I hate are Anonymous Classes and Static Blocks. We have a lot of legacy code that make use of Static Blocks and these are one of the annoying points in our push in writing unit tests. Our goal is to be able to write unit tests for classes that depend on this static initialization with minimal code changes.

到目前为止,我对同事的建议是将静态块的主体移动到私有静态方法中并将其命名为 staticInit 。然后可以从静态块内调用此方法。对于单元测试,依赖于这个类的另一个类可以很容易地使用JMockit模拟 staticInit 来做任何事情。让我们在示例中看到这一点。

So far my suggestion to my colleagues is to move the body of the static block into a private static method and call it staticInit. This method can then be called from within the static block. For unit testing another class that depends on this class could easily mock staticInit with JMockit to not do anything. Let's see this in example.

public class ClassWithStaticInit {
  static {
    System.out.println("static initializer.");
  }
}

将更改为

public class ClassWithStaticInit {
  static {
    staticInit();
  }

  private static void staticInit() {
    System.out.println("static initialized.");
  }
}

这样我们就可以在JUnit中执行以下操作。

So that we can do the following in a JUnit.

public class DependentClassTest {
  public static class MockClassWithStaticInit {
    public static void staticInit() {
    }
  }

  @BeforeClass
  public static void setUpBeforeClass() {
    Mockit.redefineMethods(ClassWithStaticInit.class, MockClassWithStaticInit.class);
  }
}

但是这个解决方案也有自己的问题。您不能在同一个JVM上运行 DependentClassTest ClassWithStaticInitTest ,因为您实际上希望静态块为<$运行c $ c> ClassWithStaticInitTest 。

However this solution also comes with its own problems. You can't run DependentClassTest and ClassWithStaticInitTest on the same JVM since you actually want the static block to run for ClassWithStaticInitTest.

完成此任务的方法是什么?或者你认为哪种更好,非基于JMockit的解决方案更干净?

What would be your way of accomplishing this task? Or any better, non-JMockit based solutions that you think would work cleaner?

推荐答案

当我遇到这个问题时,我通常做你描述的同样的事情,除了我保护静态方法所以我可以手动调用它。最重要的是,我确保可以多次调用该方法而不会出现问题(否则,就测试而言,它并不比静态初始化器更好)。

When I run into this problem, I usually do the same thing you describe, except I make the static method protected so I can invoke it manually. On top of this, I make sure that the method can be invoked multiple times without problems (otherwise it is no better than the static initializer as far as the tests go).

这个工作得相当好,我实际上可以测试静态初始化方法是否符合我的期望/希望它做什么。有时候最简单的是有一些静态初始化代码,构建一个过于复杂的系统来替换它是不值得的。

This works reasonably well, and I can actually test that the static initializer method does what I expect/want it to do. Sometimes it is just easiest to have some static initialization code, and it just isn't worth it to build an overly complex system to replace it.

当我使用这个机制时,我确保记录受保护的方法仅出于测试目的而暴露,希望其他开发人员不会使用它。这当然可能不是一个可行的解决方案,例如,如果类的接口是外部可见的(作为其他团队的某种子组件,或作为公共框架)。这是一个简单的问题解决方案,并且不需要设置第三方库(我喜欢)。

When I use this mechanism, I make sure to document that the protected method is only exposed for testing purposes, with the hopes that it won't be used by other developers. This of course may not be a viable solution, for example if the class' interface is externally visible (either as a sub-component of some kind for other teams, or as a public framework). It is a simple solution to the problem though, and doesn't require a third party library to set up (which I like).

这篇关于在Java中模拟静态块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆