vasanthraj devaraju
vasanthraj devaraju

Reputation: 148

How to write the unit test case for the Classes which are annotated with @Configuration in Spring Boot application

I have a Configuration Class, which creates the bean for RedissonClient and also Creates the CacheManager. How to create the Unit Test case for this Configuration classes.

  1. Can we write unit test case for @Configuration Class?
  2. If we can, How we need to develop.

I prefer to write the test case in Spock Framework, with Groovy. If not, using Junit or Mockito Framework. How to write the unit test case for the Classes which are annotated with @Configuration in Spring Boot application

@Configuration
public class CacheConfiguration {
    private static final String CONFIG= "Configuration";

    @Value("${redis.server.url}")
    private String redisUrl;

    @Value("${redis.server.password}")
    private String password;

    @Bean 
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress(redisUrl).setPassword(password);
        RedissonClient client = Redisson.create(config);
        return client;
    }
    @Bean
    public CacheManager redissonCacheManager(RedissonClient redissonClient) {
        Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
        config.put(CONFIG, new CacheConfig(24*60*1000, 12*60*1000));
        return new RedissonSpringCacheManager(redissonClient, config);
    }

}

Upvotes: 3

Views: 5278

Answers (2)

vasanthraj devaraju
vasanthraj devaraju

Reputation: 148

After some research and found that, we can run the embedded redis server and we can check whether we able to connect to redis server by spin up the application. I don't if this is correct or not. But by doing so, it really takes time to complete it, took around 20 seconds. Used following dependency to test this // https://mvnrepository.com/artifact/it.ozimov/embedded-redis testCompile group: 'it.ozimov', name: 'embedded-redis', version: '0.7.2'

@SpringBootTest(classes = [TestApp])
class CacheConfigurationSpec extends Specification {

@Shared
RedisServer redisServer;

def setupSpec() {
    redisServer = RedisServer.builder()
            .port(6379)
            .setting("bind 127.0.0.1")
            .setting("maxmemory 128M")
            .build()
    redisServer.start()
}

def cleanupSpec() {
    if (redisServer != null) {
        redisServer.stop()
    }
}

@Autowired
private RedissonClient redissonClient;

def "load all contexts"() {

}
}
@SpringBootApplication
class TestApp {
 static void main(String[] args){
    SpringApplication.run(TestApp.class, args)
 }
}

Upvotes: 1

Mark Bramnik
Mark Bramnik

Reputation: 42441

I think you should realize that classes annotated with @Configuration are not really java classes, or at least you should not treat them like this. I know it sound controversial, I'll explain...

So historically spring used XML configurations to declare beans.

In spring 2.5 I guess, they've introduced an annotation based method where you put annotations @Component/@Service on classes, put @Autowired wherever you want spring to inject dependencies, then spring starts, scans the classpath, detects the beans and starts the application context with these beans.

Then Spring 3.0 has introduced a Java Configuration way of doing spring related configurations:@Configuration / @Bean in a special class.

So you should view these configuration classes as a "substitution" to the methods I've described before

Now let me ask, do you think you should test and XML bean configuration on its own? Probably not... Do you think you should test that class has annotation @Component on it and all the necessary dependencies are autowired (with reflection or whatever)? Probably not.

So why you want to test the Java Config classes?

Here is another argument that you might find interesting

I've said that these classes are solely for spring to resolve the beans and it internally runs them. But spring doesn't just "run" them - it creates run-time wrapper for them to overcome some technicalities. Here is an example of one such thing:

Lest assume we have three beans: A,B,C such as B and C depend on A.


class A {}

class B {
   private A a;
   public B(A a) {this.a = a;}
}

class C {
   private A a;
   public C(A a) {this.a = a;}
}

All beans are expected to be singletons so we define the configuration like this:

@Configuration
public class MyConfig { 
   @Bean
   public A a() { return new A(); }

   @Bean
   public B b() { return new B(a()); }

   public C c() {return new C(a()); }

} 

Note that we call a() in definitions of B and C Now, let me ask you a question: If its a "regular" java code how two different invocations of method a() (in B's and C's constructor) respectively are supposed to return the same instance of A?

So spring indeed uses a lot of sophisticated code and this is what actually runs in runtime, not your class as is, but the transformed version of it and you never know what are those transformations exactly since its and internal spring thing. But is so what is the point of testing it as it is?

I believe there are more arguments like this, but the point is clear - don't test the Configuration classes on their own.

Instead you can use an integration test that will run the spring container and load all the classes required in the configuration. However, in this case you'll probably want to mock some classes (by using @MockBean for example) so it won't be a 100% accurate test.

In terms of code coverage - IMO you should exclude these classes from coverage altogether

Upvotes: 2

Related Questions