代码之家  ›  专栏  ›  技术社区  ›  sblundy

JUnit4.x中的套件执行钩子前后

  •  80
  • sblundy  · 技术社区  · 16 年前

    我正在尝试为一组集成测试执行安装和拆卸,使用JUnit4.4来执行测试。拆卸需要可靠运行。我对testng还有其他问题,所以我希望移植回junit。在运行任何测试之前和所有测试完成之后,哪些钩子可供执行?

    注意:我们使用maven 2进行构建。我试过用Maven的 pre- &安培 post-integration-test 阶段,但是,如果测试失败,maven将停止并不运行 后集成测试 ,这没有帮助。

    11 回复  |  直到 16 年前
        1
  •  111
  •   Julie    16 年前

    是的,可以在测试套件中的任何测试之前和之后可靠地运行设置和删除方法。让我用代码演示一下:

    package com.test;
    
    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;
    import org.junit.runners.Suite.SuiteClasses;
    
    @RunWith(Suite.class)
    @SuiteClasses({Test1.class, Test2.class})
    public class TestSuite {
    
        @BeforeClass
        public static void setUp() {
            System.out.println("setting up");
        }
    
        @AfterClass
        public static void tearDown() {
            System.out.println("tearing down");
        }
    
    }
    

    所以test1类看起来像:

    package com.test;
    
    import org.junit.Test;
    
    
    public class Test1 {
        @Test
        public void test1() {
            System.out.println("test1");
        }
    
    }
    

    ……你可以想象test2看起来很相似。如果运行testsuite,您将得到:

    setting up
    test1
    test2
    tearing down
    

    因此,您可以看到,设置/删除只在所有测试之前和之后分别运行。

    要点:只有在运行测试套件,而不是将test1和test2作为单独的junit测试运行时,这才有效。您提到您正在使用maven,maven surefire插件喜欢单独运行测试,而不是一个套件的一部分。在这种情况下,我建议创建一个每个测试类扩展的超类。然后,超类包含带注释的@beforeclass和@afterclass方法。虽然没有上述方法那么干净,但我认为它对你会有用的。

    对于失败测试的问题,可以设置maven.test.error.ignore,以便在失败测试上继续生成。这不建议作为一个持续的实践,但它应该让您的功能,直到您的所有测试通过。有关详细信息,请参见 maven surefire documentation 是的。

        2
  •  32
  •   Martin Vysny    11 年前

    我的一位同事建议如下:可以使用自定义RunListener并实现testRunFinished()方法: http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org.junit.runner.Result)

    注册RunListEnter只需配置SureFi火插件如下: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html “使用自定义侦听器和报告器”部分

    此配置也应由故障保护插件选择。 这个解决方案很好,因为您不必指定套件、查找测试类或其他任何东西—它让maven发挥其魔力,等待所有测试完成。

        4
  •  7
  •   Community miroxlav    12 年前

    使用注释,可以执行以下操作:

    import org.junit.*;
    import static org.junit.Assert.*;
    import java.util.*;
    
    class SomethingUnitTest {
        @BeforeClass
        public static void runBeforeClass()
        {
    
        }
    
        @AfterClass
        public static void runAfterClass()
        {  
    
        }
    
        @Before  
        public void setUp()
        {
    
        }
    
        @After
        public void tearDown()
        {
    
        }
    
        @Test
        public void testSomethingOrOther()
        {
    
        }
    
    }
    
        5
  •  3
  •   carym    15 年前

    在这里,我们

    • 升级到JUnit4.5,
    • 编写注释以标记需要测试服务的每个测试类或方法,
    • 为每个注释编写处理程序,这些注释包含静态方法来实现服务的设置和拆卸,
    • 扩展通常的运行程序以定位测试上的注释,在适当的点将静态处理程序方法添加到测试执行链中。
        6
  •  2
  •   Binod Pant    14 年前

    至于“注意:我们使用maven 2进行构建。我尝试过使用maven的集成前和集成后测试阶段,但是,如果测试失败,maven将停止并不运行集成后测试,这毫无帮助。”

    您可以尝试使用故障保护插件,我认为它具有确保清除发生的功能,而不考虑安装或中间阶段的状态

        7
  •  2
  •   Community miroxlav    7 年前

    如果所有的测试可以扩展一个“技术”类,并且在同一个包中,你可以做一个小技巧:

    public class AbstractTest {
      private static int nbTests = listClassesIn(<package>).size();
      private static int curTest = 0;
    
      @BeforeClass
      public static void incCurTest() { curTest++; }
    
      @AfterClass
      public static void closeTestSuite() {
          if (curTest == nbTests) { /*cleaning*/ }             
      }
    }
    
    public class Test1 extends AbstractTest {
       @Test
       public void check() {}
    }
    public class Test2 extends AbstractTest {
       @Test
       public void check() {}
    }
    

    请注意,此解决方案有很多缺点:

    • 必须执行包的所有测试
    • 必须子类化“techincal”类
    • 不能在子类中使用@BeforeClass和@AfterClass
    • 如果只执行包中的一个测试,则不会进行清理

    有关信息:listclassein()=> How do you find all subclasses of a given class in Java?

        8
  •  0
  •   user15299    16 年前

    据我所知,在JUnit没有这样做的机制,但是您可以尝试子类套件,并用提供钩子的版本重写Run()方法。

        9
  •  0
  •   Anurag Sharma    14 年前

    由于Maven SureFi火插件不首先运行套件类,而是对待套件和测试类相同,所以我们可以配置插件如下,只启用套件类和禁用所有的测试。套件将运行所有测试。

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <includes>
                        <include>**/*Suite.java</include>
                    </includes>
                    <excludes>
                        <exclude>**/*Test.java</exclude>
                        <exclude>**/*Tests.java</exclude>
                    </excludes>
                </configuration>
            </plugin>
    
        10
  •  0
  •   Aaron Digulla    14 年前

    我想只有这样才能得到你想要的功能

    import junit.framework.Test;  
    import junit.framework.TestResult;  
    import junit.framework.TestSuite;  
    
    public class AllTests {  
        public static Test suite() {  
            TestSuite suite = new TestSuite("TestEverything");  
            //$JUnit-BEGIN$  
            suite.addTestSuite(TestOne.class);  
            suite.addTestSuite(TestTwo.class);  
            suite.addTestSuite(TestThree.class);  
            //$JUnit-END$  
         }  
    
         public static void main(String[] args)  
         {  
            AllTests test = new AllTests();  
            Test testCase = test.suite();  
            TestResult result = new TestResult();  
            setUp();  
            testCase.run(result);  
            tearDown();  
         }  
         public void setUp() {}  
         public void tearDown() {}  
    } 
    

    我在eclipse中使用类似的东西,所以我不确定它在该环境之外的可移植性如何

        11
  •  0
  •   Community miroxlav    7 年前

    如果您不想创建一个套件,并且必须列出所有的测试类,那么可以使用反射动态地查找测试类的数量,并在基类@afterclass中倒计时,以便只进行一次拆卸:

    public class BaseTestClass
    {
        private static int testClassToRun = 0;
    
        // Counting the classes to run so that we can do the tear down only once
        static {
            try {
                Field field = ClassLoader.class.getDeclaredField("classes");
                field.setAccessible(true);
    
                @SuppressWarnings({ "unchecked", "rawtypes" })
                Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
                for (Class<?> clazz : classes) {
                    if (clazz.getName().endsWith("Test")) {
                        testClassToRun++;
                    }
                }
            } catch (Exception ignore) {
            }
        }
    
        // Setup that needs to be done only once
        static {
            // one time set up
        }
    
        @AfterClass
        public static void baseTearDown() throws Exception
        {
            if (--testClassToRun == 0) {
                // one time clean up
            }
        }
    }
    

    如果您喜欢使用@ BeeExLASS而不是静态块,您也可以使用布尔标志在第一次调用时只做一次反射计数和测试设置。希望这能帮上忙,我花了一个下午才想出一个比枚举一个套件中所有类更好的方法。

    现在您需要做的就是为所有测试类扩展这个类。我们已经有了一个基类来为我们所有的测试提供一些普通的东西,所以这是我们最好的解决方案。

    灵感来自这个答案 https://stackoverflow.com/a/37488620/5930242

    如果你不想把这个类扩展到任何地方,这个最后的答案可能会满足你的要求。