【问题标题】:Intercepting JUnit Assert functions拦截 JUnit 断言函数
【发布时间】:2026-01-13 20:25:01
【问题描述】:

当 JUnit 中的断言失败时,我想做一些“自己的事情”。我想要这个:

public class MyAssert extends org.junit.Assert {

    // @Override
    static public void fail(String message) {
        System.err.println("I am intercepting here!");
        org.junit.Assert.fail(message);
    }
}

当然,这是行不通的,因为你不能覆盖静态方法。但如果可以,那就太好了,因为像assertTrue() 这样的每个断言函数都会调用fail() 方法。因此,我可以轻松拦截每个断言。

是否有任何方法可以在这里做我想做的事情,而无需实现所有不同风格的assert...

【问题讨论】:

    标签: junit interception


    【解决方案1】:

    您应该查看在 Junit 4.7 中引入的规则。特别是TestWatchman:

    TestWatchman 是记录测试操作的规则的基类,无需修改它。例如,这个类将记录每个通过和失败的测试:

    http://junit-team.github.io/junit/javadoc/4.10/org/junit/rules/TestWatchman.html

    它允许您定义一个可以处理失败测试的 MethodRule(从 javadoc 复制):

       @Rule
        public MethodRule watchman= new TestWatchman() {
                @Override
                public void failed(Throwable e, FrameworkMethod method) {
                        watchedLog+= method.getName() + " " + e.getClass().getSimpleName()
                                        + "\n";
                }
    
                @Override
                public void succeeded(FrameworkMethod method) {
                        watchedLog+= method.getName() + " " + "success!\n";
                }
        };
    
        @Test
        public void fails() {
                fail();
        }
    
        @Test
        public void succeeds() {
        }
    

    根据评论,TestWatchman 在较新版本的 Junit 中被取消并替换为 TestWatcher(但功能相同):

    http://junit-team.github.io/junit/javadoc/4.10/org/junit/rules/TestWatcher.html

    【讨论】:

    • TestWatchman 似乎已被弃用,取而代之的是 TestWatcher。 (上面的链接坏了)
    【解决方案2】:

    对于单个断言,您可以捕获 AssertionError - 以下对我有用。当您只是偶尔需要该功能时,它很有用。

    try {
        Assert.assertEquals("size", classes.length, containerList.size());
    } catch (AssertionError e) {
        System.err.println("ERROR");
        for (AbstractContainer container : containerList) {
            System.err.println(container.getClass());
        }
        throw (new RuntimeException("Failed", e));
    }
    

    【讨论】:

      【解决方案3】:

      您可以编写一个类来实现 Assert 中所有方法的完全相同的签名,然后委托给 Assert 方法。

      public class MyAssert {
          static public void assertTrue(String message, boolean condition) {
              Assert.assertTrue(message, condition);
          }
      
          ...
      
          static public void fail(String message) {
              System.err.println("I am intercepting here!");
              Assert.fail(message);
          }
      }
      

      没有完全重新实现所有方法,但仍然很乏味。您的 IDE 可能会帮助生成委托方法。

      【讨论】: