LoginSignup
1
1

More than 3 years have passed since last update.

SpringでAOPをテストしたいときはProxyFactoryが便利!

Last updated at Posted at 2020-03-18

概要

  • 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
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1