如何排除junit.framework.TestCase被Bytebuddy的@Origin

时间:2017-04-19 17:35:44

标签: java unit-testing junit byte-buddy

我试图在执行期间运行JUnit4测试,然后用Bytebuddy(版本1.2.3)拦截测试,以找出测试中的哪些方法是mutator方法(更改底层类中的变量)。整个过程在正常的JUnit测试中运行良好,但是当我尝试执行完全相同的测试但扩展junit.framework.TestCase时,进程崩溃了。我设法将错误限制为以下内容:当我尝试调试时,我收到许多条目clazz="junit.framework.testcase"(请参阅Interceptor.java),这是导致崩溃的类。

我的问题如下。如何排除TestCase类被截获?我尝试了以下陈述:

  1. ElementMatchers.not(ElementMatchers.namedIgnoreCase("junit.framework.testcase"))
  2. ElementMatchers.not(ElementMatchers.is(junit.framework.TestCase.class))
  3. ElementMatchers.not(ElementMatchers.nameContains("junit.framework"))
  4. 使用以下代码,我尝试接收控制台输出:

    intercepted: tests.producttest
    running testSquarPrice
    intercepted: example.product
    finished testSquarPrice
    

    但结果始终是以下输出,即使我尝试排除junit.framework.testcase

    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: junit.framework.testcase
    intercepted: tests.producttest
    running testSquarPrice
    intercepted: example.product
    finished testSquarPrice
    intercepted: junit.framework.testcase
    

    这是我的代码:
    Starter.java

    import introspect.Agent;
    
    public class Starter {
        public static void main(String[] args) {
            Agent x = new Agent();
            x.run();
        }
    }
    

    Agent.java

    package introspect;
    
    import org.junit.runner.Request;
    
    import net.bytebuddy.dynamic.DynamicType.Builder;
    
    public class Agent {
    
        public Agent() {
        final Interceptor interceptor = new Interceptor();
        new AgentBuilder.Default()
                .type(ElementMatchers.not(ElementMatchers.named("junit.framework.testcase"))
                        .and(ElementMatchers.nameStartsWithIgnoreCase("example")
                                .or(ElementMatchers.nameEndsWithIgnoreCase("test"))),
                        ElementMatchers.not(ElementMatchers.isBootstrapClassLoader()))
                .transform(new AgentBuilder.Transformer() {
                    @Override
                    public Builder<?> transform(Builder<?> builder, TypeDescription arg1, ClassLoader arg2) {
                        return builder
                                .method(ElementMatchers.isPublic()
                                        .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))))
                                .intercept(MethodDelegation.to(interceptor).filter(ElementMatchers.named("intercept")));
                    }
                }).installOn(ByteBuddyAgent.install());
    }
    
        public void run() {
            JUnitCore junit = new JUnitCore();
    
            Request request = Request.method(ProductTest.class, "testSquarPrice");
            junit.run(request);
        }
    }
    

    Interceptor.java

    package introspect;
    
    import java.lang.reflect.Method;
    
    import net.bytebuddy.implementation.bind.annotation.AllArguments;
    import net.bytebuddy.implementation.bind.annotation.Origin;
    import net.bytebuddy.implementation.bind.annotation.RuntimeType;
    import net.bytebuddy.implementation.bind.annotation.SuperCall;
    import net.bytebuddy.implementation.bind.annotation.This;
    
    public class Interceptor {
    
        @RuntimeType
        public Object intercept(@Origin Method m, @SuperCall Callable<?> zuper, @AllArguments Object[] args,
                @This Object thiz) throws Exception {
    
            // get the name of the intercepted class
            String clazz = m.getDeclaringClass().getName().toLowerCase();
            System.out.println("intercepted: "+clazz);
    
            return zuper.call();
        }
    }
    

    ProductTest.java

    package tests;
    
    public class ProductTest extends TestCase{
    
        @Test
        public void testSquarPrice() {
            System.out.println("running testSquarPrice");
    
            Product p = new Product();
    
            int re = p.squarPrice(10);
    
            assertTrue(re == 100);
    
            System.out.println("finished testSquarPrice");
        }
    }
    

    Product.java

    package example;
    
    public class Product {
    
        public int count, price, index;
    
        public Product() {
            index = 0;
        }
    
        public int squarPrice(int price) {
            index++;
            return price * price;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

ElementMatchers.not(ElementMatchers.is(junit.framework.TestCase.class)),您只能排除班级本身。您不排除此类声明的方法以及其他类继承的方法。你想做的可能更像是:

method(ElementMatchers.isPublic()
  .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))))
  .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(TestCase.class))))

甚至喜欢:

method(ElementMatchers.isPublic()
  .and(ElementMatchers.isDeclaredBy(arg1)))

在后一种情况下,您只拦截声明的方法,但绝不会覆盖继承的方法。