我试图在执行期间运行JUnit4测试,然后用Bytebuddy(版本1.2.3)拦截测试,以找出测试中的哪些方法是mutator方法(更改底层类中的变量)。整个过程在正常的JUnit测试中运行良好,但是当我尝试执行完全相同的测试但扩展junit.framework.TestCase时,进程崩溃了。我设法将错误限制为以下内容:当我尝试调试时,我收到许多条目clazz="junit.framework.testcase"
(请参阅Interceptor.java),这是导致崩溃的类。
我的问题如下。如何排除TestCase类被截获?我尝试了以下陈述:
ElementMatchers.not(ElementMatchers.namedIgnoreCase("junit.framework.testcase"))
ElementMatchers.not(ElementMatchers.is(junit.framework.TestCase.class))
ElementMatchers.not(ElementMatchers.nameContains("junit.framework"))
使用以下代码,我尝试接收控制台输出:
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;
}
}
答案 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)))
在后一种情况下,您只拦截声明的方法,但绝不会覆盖继承的方法。