概要
- AOPの設定が動くようになっているかをテストしたい
- しかし、中で外部への副作用(例: トランザクション、ログ出力...etc)を及ぼす処理を行っている場合テストがしづらい
- そんなときはProxyFactoryが便利
まずは普通のテストコードを書いてみる
前提として以下のServiceクラスとMethodInterceptorを用意。
AOPの対象Service
@Service
class SampleService {
fun execute() {
println("SampleService#execute")
}
}
Interceptor
class SampleInterceptor(
private val name: String
) : MethodInterceptor {
override fun invoke(invocation: MethodInvocation?): Any? {
println("intercept by $name")
return invocation?.proceed()
}
}
class SampleServicePointCut : StaticMethodMatcherPointcut() {
override fun matches(method: Method, @Nullable targetClass: Class<*>?): Boolean {
return targetClass?.let { SampleService::class.java.isAssignableFrom(it) } ?: false
}
}
config
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
class AopConfig {
@Bean
fun interceptorA(): Advisor {
return DefaultPointcutAdvisor(SampleServicePointCut(), SampleInterceptor("configured interceptor"))
}
}
テストコード
@SpringBootApplication
class SpringTestApplication
@RunWith(SpringRunner::class)
@SpringBootTest(classes = [SpringTestApplication::class])
internal class SampleServiceTest {
@Autowired
private lateinit var service: SampleService
@Test
fun test() {
service.execute()
}
}
実行結果
intercept by configured interceptor
SampleService#execute
ProxyFactoryを使って以下のようにテストコードを書いてみる
ProxyFactoryを使ったテストコード
@Test
fun testByProxy() {
val factory = ProxyFactory(SampleService())
factory.addAdvisor(DefaultPointcutAdvisor(SampleServicePointCut(), SampleInterceptor("Proxy")))
val proxy = factory.proxy as SampleService
proxy.execute()
}
実行結果
intercept by Proxy
SampleService#execute
KotlinならUtil関数つくってもいいかも
Extensionを使ってutil関数をつくっておくのもよい。
kotlinのextensionを使った例ProxyFactoryを使ったテストコード
@Test
fun testByProxy() {
val proxy = SampleService().proxy {
addAdvisor(DefaultPointcutAdvisor(SampleServicePointCut(), SampleInterceptor("Proxy")))
}
proxy.execute()
}
@Suppress("UNCHECKED_CAST")
fun <T : Any> T.proxy(settings: ProxyFactory.() -> Unit): T {
return ProxyFactory(this).also { settings(it) }.proxy as T
}
@Aspectを使っている場合はAspectJProxyFactory
ServiceとConfig
@Aspect
@Component
class SampleAspect(
private val name: String = ""
) {
@Before("execution(* SampleAspectService.*(..))")
fun advice() {
println("advice by $name")
}
}
@Service
class SampleAspectService {
fun execute() {
println("SampleAspectService#execute")
}
}
テストコード
@Test
fun testAspectProxy() {
val factory = AspectJProxyFactory(SampleAspectService())
factory.addAspect(SampleAspect("proxy"))
val proxy = factory.getProxy() as SampleAspectService
proxy.execute()
}
実行結果
advice by proxy
SampleAspectService#execute