Search code examples
javaspringintegration-testing

How to assert whether autowired instance is right class?


My Java project uses Spring. I have an interface Connector that's implemented by several classes, ConnectorV1, ConnectorV2, and so on.

The classes are annotated @Component("V1"), @Component("V2"), and so on, to distinguish them. The classes are configured for request scope. For example:

@Component("V2")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
public class ConnectorV2 implements Connector {

One of my integration test classes uses @Autowired @Qualifier("V2") to obtain an instance of ConnectorV2 as classUnderTest and test it. I lately found that I had accidentally wired the ConnectorV1 and received weird test results. I'd therefore like to double-check in one of the test methods that I really have the right class at hand.

Unfortunately, all my attempts to assert the concrete class of classUnderTest failed because the instance at runtime is first of all a com.sun.proxy$Proxy{someNumber}. Even flexible assertions like AssertJ's assertThat(classUnderTest).isInstanceOf(ConnectorV2.class) fail to identify the actual class.

Is there a way to look beyond that proxy and see the "real" class that it encapsulates?


Solution

  • you can use AopProxyUtils.ultimateTargetClass(controller). Here is a simple example:

    @SpringBootTest(classes = Question.ControllerV2.class)
    public class Question {
    
        @Component("V2")
        @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
        static class ControllerV2 implements Controller {}
    
        interface Controller {}
    
        @Autowired
        @Qualifier("V2")
        private Controller controller;
    
        @Test
        void testInstanceOf() {
            Class<?> clazz = AopProxyUtils.ultimateTargetClass(controller);
            Assertions.assertThat(clazz).isEqualTo(ControllerV2.class);
        }
    
    }
    

    Though, are you sure this is a good idea? This will couple the test to the implementation. The B.D.D. approach suggests testing the behavior and abstracting away the implementation details from the test - making refactoring easier.