【问题标题】:Junit before class ( non static )Junit 课前(非静态)
【发布时间】:2011-02-19 00:24:04
【问题描述】:

是否有任何最佳实践可以让 Junit 在测试文件中执行一次函数,并且它也不应该是静态的。

喜欢@BeforeClass 的非静态函数?

这是一个丑陋的解决方案:

@Before void init(){
    if (init.get() == false){
        init.set(true);
        // do once block
    }
}

这是我不想做的事情,我正在寻找一个集成的 junit 解决方案。

【问题讨论】:

  • 嗯,我有一个相当大的测试文件层次结构和基础测试文件,我需要在子测试类中覆盖这个操作。
  • 我遇到了同样的问题,即只有许多参数化测试中的第一个应该执行登录。
  • 请注意,“丑陋”的解决方案,即与普通 JUnit 一起工作的解决方案,不考虑拆解测试。

标签: java junit


【解决方案1】:

一个简单的 if 语句似乎也很有效:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {

    public static boolean dbInit = false;

    @Autowired
    DbUtils dbUtils;

    @Before
    public void setUp(){

        if(!dbInit){

            dbUtils.dropTables();
            dbUtils.createTables();
            dbInit = true;

        }
    }

 ...

【讨论】:

  • 又好又简单!但是看不到一种方法可以简单地调整它来制作一个非静态的@AfterClass 等效项,在所有测试都运行后就拆除?
  • 请参阅here 了解此方法的更新,该方法适用于使用继承的测试类。
【解决方案2】:

使用空构造函数是最简单的解决方案。您仍然可以覆盖扩展类中的构造函数。

但它并不是所有继承的最佳选择。这就是 JUnit 4 使用注解的原因。

另一种选择是在工厂/实用程序类中创建一个辅助方法并让该方法完成工作。

如果您使用的是 Spring,则应考虑使用 @TestExecutionListeners 注释。 像这样的测试:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({CustomTestExecutionListener.class, 
     DependencyInjectionTestExecutionListener.class})
@ContextConfiguration("test-config.xml")
public class DemoTest {

Spring 的 AbstractTestExecutionListener 包含例如这个您可以覆盖的空方法:

public void beforeTestClass(TestContext testContext) throws Exception {
    /* no-op */
}

注意:在添加自定义TestExecutionListeners 时不要忽略/错过DependencyInjectionTestExecutionListener。如果你这样做了,所有的自动连线都将是null

【讨论】:

  • +1 当我想使用 DbUnit 并且每个类只加载一次数据集时,这种技术解决了我的问题
  • +1 这是完美的……对于那些不依赖于古老版本的 Spring 的人来说。 :(
  • 这个beforeTestClass()会在上下文初始化之前还是之后调用?
  • @Dims 上下文初始化后
【解决方案3】:

如果您不想为一次性初始化设置静态初始化程序并且不特别想使用 JUnit,请查看 TestNG。 TestNG 支持具有多种配置选项的非静态一次性初始化,所有这些都使用注释。

在 TestNG 中,这相当于:

@org.testng.annotations.BeforeClass
public void setUpOnce() {
   // One time initialization.
}

为了拆解,

@org.testng.annotations.AfterClass
public void tearDownOnce() {
   // One time tear down.
}

对于与 JUnit 4 的 @Before@After 等效的 TestNG,您可以分别使用 @BeforeMethod@AfterMethod

【讨论】:

    【解决方案4】:

    轻松使用@BeforeAllMethods/@AfterAllMethods 注解在实例上下文(非静态)中运行方法,所有注入的值都将可用。

    为此有一个特殊的测试库:

    https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0

    https://bitbucket.org/radistao/before-after-spring-test-runner/

    唯一的限制:仅适用于 Spring 测试。

    (我是这个测试库的开发者)

    【讨论】:

      【解决方案5】:

      我从未尝试过,但也许你可以创建一个无参数的构造函数并从那里调用你的函数?

      【讨论】:

      • 这行得通,问题是我需要在扩展此基础测试类的类中覆盖此操作
      • @Roman:哦,现在我明白了。将此添加到您的帖子中,此评论使事情更加清晰。
      • 构造函数将被调用多少次测试用例。对于每个测试方法,都会创建新的 Test 类对象。所以,在这里使用构造函数不是解决方案
      • 这也不适用于依赖于已构建对象的依赖注入。
      【解决方案6】:

      The article 讨论这个问题的 2 个非常好的解决方案:

      1. 带有自定义 Runner 的“clean”junit(使用接口,但您可以使用自定义注释扩展它,例如 @BeforeInstance)
      2. Espen 之前提到的 Spring 执行侦听器。

      【讨论】:

        【解决方案7】:

        更新:请参阅 Cherry 的评论,了解为什么下面的建议有缺陷。(我将答案保留在此处而不是删除,因为评论可能会向其他人提供关于为什么这样做的有用信息不起作用。)


        如果使用依赖注入(例如 Spring),另一个值得考虑的选项是 @PostConstruct。这将保证依赖注入是完整的,而在构造函数中不会出现这种情况:

        @PostConstruct
        public void init() {
            // One-time initialization...
        }
        

        【讨论】:

        • 在 Junit 测试中非常糟糕的解决方案。 Junit 每次运行测试方法时都会创建测试类实例。所以如果类中有 6 个测试方法,一个类构造函数,@Before@After 方法将被调用 6 次!所以在这种情况下@PostConstruct 的行为类似于@Before 注释。您可以简单地对其进行测试:只需将 2 个测试方法放在测试类中,添加 @PostConstruct public void init() {System.out.println("started");} 并在日志中查看它打印了多少次。
        • 对于信息,我刚刚遇到JUnit documentation,它证实了上面评论中关于 JUnit 为每个 @Test 运行创建一个实例的描述:“要运行该方法,JUnit 首先构造然后类的一个新实例调用带注释的方法。”
        【解决方案8】:

        只需使用@BeforeClass:

        @BeforeClass
        public static void init() {
        }
        

        init 是非静态的没有意义,因为每个测试都在单独的实例中运行。实例 init 在其上运行不会匹配任何测试的实例。

        您可能希望它是非静态的唯一原因是在子类中覆盖它,但您可以这样做 也使用静态方法。同名即可,只会调用子类init方法。

        【讨论】:

        • 整个问题是关于以非静态方式执行此操作的可能性,如果您需要类上的一些实例变量,则需要这样做。
        • @SimonForsberg 是的,我说这个问题是 XY 问题。操作人员表示,问题是覆盖了子类中的行为。如果示例需要实例变量,那么我可能会提出其他建议。
        • @SimonForsberg 这就是我所说的评论。怎么样?
        猜你喜欢
        • 2016-09-02
        • 1970-01-01
        • 2019-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多