使用 Guice 和 JMockit 对拦截器进行单元测试
Unit Testing Interceptors with Guice and JMockit
我不熟悉为方面编写单元测试。在阅读了一些单元测试方面的内容后,我得出的结论是要编写两种类型的测试:测试方面的逻辑,以及测试拦截(即拦截是否正确)。我有一个逻辑部分的单元测试。然而,我一直在努力想出一个拦截部分的测试。
我正在使用 JUnit 4、JMockit 和 Guice(针对 CDI 和 AOP)编写测试。
下面的class是我的方面,它记录了一个方法调用的执行时间。
class ExecutionTime implements MethodInterceptor {
private static final Logger logger = ...
public Object invoke(MethodInvocation invocation) throws Throwable {
final long start = System.nanoTime();
try {
return invocation.proceed();
} finally {
final long end = System.nanoTime();
logger.trace(...);
}
}
}
在 Guice 中,我创建了一个 Module
用于初始化注入器。代码如下。绑定表示任何 class 和未用 @DoNotProfile
注释的方法将被 ExecutionTime
方面忽略。
class ProfilingModule extends AbstractModule {
public void configure() {
bindInterceptor(not(annotatedWith(DoNotProfile.class)),
not(annotatedWith(DoNotProfile.class)), new ExecutionTime());
}
}
接下来,我定义了一个测试class,我可以在其中测试方法是否被正确拦截。一些方法用 @DoNotProfile
.
注释
class TestClass {
public void methodA() {}
@DoNotProfile public void methodB() {}
...
}
最后,在我的测试中class,我的测试方法中有以下代码。
@Test
public void test() throws Throwable {
Injector injector = Guice.createInjector(new ProfilingModule());
... // not sure what to do next
}
我不确定下一步该做什么。我尝试了以下方法。
- 我创建了另一个拦截器来拦截
ExecutionTime
class 的 invoke
方法。但是,我无法让它工作。
- 我创建了一个与
ExecutionTime
具有相同绑定的测试拦截器和一个与之配套的测试模块。即.createInjector(new TestModule())
。但我意识到这违背了本次测试的目的,即测试接线是否正常工作。
我感谢任何关于此事的见解和帮助。
如果您运行遇到这类问题,请退后一步,重新思考:我的应用程序的构建块是什么?然后将这些作为任意单位进行测试。
您的情况:"Does the MethodInterceptor call the logger with the right values" 和 "Does the module correctly bind the ExecutionListener"。我假设你已经完成了第一个。
对于第二个:覆盖单元测试中的模块以为 ExecutionListener 提供模拟,然后根据注释的存在验证其 "invoke" 方法是否被调用 called/not。
由于 MethodInterceptors 只能绑定为具体实例,最简单的方法是为传递 ExecutionListener 实例的模块提供一个构造函数。然后你可以使用一个新实例作为默认实例并在测试中传递一个模拟。
我不熟悉为方面编写单元测试。在阅读了一些单元测试方面的内容后,我得出的结论是要编写两种类型的测试:测试方面的逻辑,以及测试拦截(即拦截是否正确)。我有一个逻辑部分的单元测试。然而,我一直在努力想出一个拦截部分的测试。
我正在使用 JUnit 4、JMockit 和 Guice(针对 CDI 和 AOP)编写测试。
下面的class是我的方面,它记录了一个方法调用的执行时间。
class ExecutionTime implements MethodInterceptor {
private static final Logger logger = ...
public Object invoke(MethodInvocation invocation) throws Throwable {
final long start = System.nanoTime();
try {
return invocation.proceed();
} finally {
final long end = System.nanoTime();
logger.trace(...);
}
}
}
在 Guice 中,我创建了一个 Module
用于初始化注入器。代码如下。绑定表示任何 class 和未用 @DoNotProfile
注释的方法将被 ExecutionTime
方面忽略。
class ProfilingModule extends AbstractModule {
public void configure() {
bindInterceptor(not(annotatedWith(DoNotProfile.class)),
not(annotatedWith(DoNotProfile.class)), new ExecutionTime());
}
}
接下来,我定义了一个测试class,我可以在其中测试方法是否被正确拦截。一些方法用 @DoNotProfile
.
class TestClass {
public void methodA() {}
@DoNotProfile public void methodB() {}
...
}
最后,在我的测试中class,我的测试方法中有以下代码。
@Test
public void test() throws Throwable {
Injector injector = Guice.createInjector(new ProfilingModule());
... // not sure what to do next
}
我不确定下一步该做什么。我尝试了以下方法。
- 我创建了另一个拦截器来拦截
ExecutionTime
class 的invoke
方法。但是,我无法让它工作。 - 我创建了一个与
ExecutionTime
具有相同绑定的测试拦截器和一个与之配套的测试模块。即.createInjector(new TestModule())
。但我意识到这违背了本次测试的目的,即测试接线是否正常工作。
我感谢任何关于此事的见解和帮助。
如果您运行遇到这类问题,请退后一步,重新思考:我的应用程序的构建块是什么?然后将这些作为任意单位进行测试。
您的情况:"Does the MethodInterceptor call the logger with the right values" 和 "Does the module correctly bind the ExecutionListener"。我假设你已经完成了第一个。
对于第二个:覆盖单元测试中的模块以为 ExecutionListener 提供模拟,然后根据注释的存在验证其 "invoke" 方法是否被调用 called/not。
由于 MethodInterceptors 只能绑定为具体实例,最简单的方法是为传递 ExecutionListener 实例的模块提供一个构造函数。然后你可以使用一个新实例作为默认实例并在测试中传递一个模拟。