【问题标题】:How to force the static block running in each test method?如何强制在每个测试方法中运行静态块?
【发布时间】:2011-04-25 23:09:10
【问题描述】:

当我执行多个 JUnit 测试时,我发现静态块只运行一次。 如何强制它为每种测试方法运行?我使用的是最新的 JUnit 4.8.2

另外,根据 xUnit 的设计原则,每个方法都应该完全独立于其他方法。为什么静态块只执行一次?

@Test TestMethod1 () {
       Accounts ac = new Accounts();
       ac.method1(); //kill the thread inside
}

@Test TestMethod2 () {
       Accounts ac = new Accounts();
       ac.method2(); // the thread is no longer available!!
}

class Accounts {
   static {
       // initalize one thread to monitor something
   }
}

这甚至发生在 TestMethod1TestMethod2 位于不同的测试类中时。

【问题讨论】:

  • 请展示一些代码来解释你如何运行它
  • 如果你想在每个@Test 运行之前初始化一些东西,在@Before 注释方法中进行

标签: java unit-testing junit


【解决方案1】:

静态块仅在类加载时执行,因为它们就是:类初始化器。让一个静态块运行多次需要你卸载类(这不是一件容易的事......)。

如果您需要使用静态块,您可以想出一些方法来测试它们。为什么不将块解包到公共(静态)方法中?在那个世界里你所要做的就是测试方法:

 static {
      staticInitMethod();
 }

 public static void staticInitMethod(){
      //insert initialization code here
 }

你也可以只使用一个普通的初始化器

 {//not static
      //insert initialization code here
 }

虽然,事实上大多数代码根本不需要使用这样的初始化器。

编辑:原来 Oracle 喜欢静态方法方法 http://download.oracle.com/javase/tutorial/java/javaOO/initial.html

【讨论】:

    【解决方案2】:

    为什么静态块只执行一次?

    因为这是静态初始化块的重点!

    或者换一种说法,如果你想让一些初始化代码执行多次,把它放在一个常规的构造函数或方法中,或者(在极少数情况下)一个非静态初始化块。


    在 JUnit 上下文中,使用setUp()tearDown() 方法实现测试启动和关闭代码的常规方式。


    如果您尝试在自己的代码中对静态初始化的执行进行单元测试,我认为您将走上一条艰难的道路。但是,对具有静态状态的代码(例如单例)进行单元测试总是很困难......这就是人们认为静态状态是一个坏主意的原因之一。

    • 考虑使用依赖注入(又名控制反转)框架而不是单例。

    • 或者,考虑修改单例/静态初始化代码以使其更易于测试。例如,添加一个允许测试重新执行初始化的静态方法。 (在你说这打破了单例模式之前:是的,我知道。你需要在设计/实现“纯度”和易于测试之间做出选择。)

    【讨论】:

    • 但是在Junit框架中,每个测试方法都应该完全独立于另一个?
    • 每个 JUnit 测试类都可以有自己的 startup()shutdown()。如果您希望测试方法完全独立,您可以将每个方法放在自己的类中。
    • @Stephen,单例模式有时很有用。
    • 是的......但它也给单元测试带来了严重的问题。许多人认为依赖注入提供了一种更简洁的替代单例。这是您的选择,但可测试性是受该选择影响的事情之一。你不能同时拥有它...
    • @user:如果你在处理单例,那么你应该这么说。
    【解决方案3】:

    是用于测试类的静态代码吗?

    如果代码是静态的以便测试可以共享,那么您需要将代码移动到它自己的类中。然后要么让测试类构造函数实例化一个静态实例,要么创建一个做同样事情的测试套件。

    如果您希望每个测试独立,那么将您在静态块中所做的事情移动到 setup()/teardown() 方法中,这就是它们的用途。

    【讨论】:

      【解决方案4】:

      当第一次类加载到 JVM 时,静态块只执行一次。 Junit 提供@Before 注释,主要用于测试用例所需的初始化。这可用于执行类的静态块。例如我有以下课程Car

          public class Car implements Vehicle{
      
              private String type = "lmv";    
              static {            
                  VehicleFactoryWithoutRefl.getInstance().registerVehicle("car", new Car());
              }
              @Override
              public void moveForward() {
              }
      
              @Override
              public String getType() {
                  return type;
              }
      
              @Override
              public Vehicle createVehicle() {
                  return new Car();
              }
      
      
      
          }
      

      我想在创建汽车实例之前在 Junit 中执行这个类的静态块。我必须使用class.forName("package.ClassName") Junit 代码在setUp() 中加载此类。

        public class TestFactory {
      
              @Before
              public void setUp() {
                  try {
                      Class.forName("com.cg.dp.factory.Car");
                  } catch (ClassNotFoundException e) {
                      //e.printStackTrace();
                  }
              }
      
              @Test
              //@Ignore
              public void testFactoryInstanceWithoutRefl() {
                  Vehicle v1 = VehicleFactoryWithoutRefl.getInstance().newVehicle("car");
                  assertTrue(v1 instanceof Car);
              }
          }
      

      【讨论】:

        【解决方案5】:

        嗯...让它非静态?您也可以拥有实例初始化程序块(与静态块相同,只是没有static 关键字)。但测试设置代码实际上应该进入显式的setUp()@Before 方法。

        【讨论】:

        • 我认为这里的重点是通过 JUnit test 静态初始化,而不是重新设计正在测试的类。因此,请证明每个静态方法在第一次调用时(因此加载类并导致静态初始化)正常工作。不过可能是错的。
        • 我需要一个静态块来确保每个对象都有一些共同点。
        • @user - 您不必必须。还有其他方法可以分享共同的事物。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-26
        • 2013-11-24
        • 2021-05-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多