2

I have a Spring Boot project for which one of the developers has written Integration tests against an in-memory DB. Here is some background before I put my question :
We have following Maven modules :
1) web-persistence : which store all entities and interfaces and corresponding implementations. All these classes are in package com.mycompany.persistence.
2) web-services : which stores all our rest controllers and spring security related classes. These are all in package com.mycompany.services
3) web-services module has maven module dependency on web-persistence module.
4) In web-services module we have defined a service UserContextServiceImpl which is implementation of interface IUserContextService. This service basically encapsulates Spring's SecurityContextHolder functionality by exposing only those parts of a current user related information which is needed through its methods so that everywhere we don't have to use SecurityContextHolder. The implementation class is annotated with @Service("userContextService").
5) Interface IUserContextService is in persistence module. There is another class AppDependecyHeper in persistence module which implements ApplicationContextAware and returns UserContextService's concrete instance by calling appContext.getBean('userContextService') where appContext is holding ApplicationContext when application is initialized.
6) Now we don't want to expose Spring Security classes in persistence module(for reasons which are out of context here) and hence above arrangement of getting current user information through a service by calling getBean() method of applicationContext in persistence layer class AppDependencyHelper. This information is then used to update audit fields createdBy and modifiedBy using an EntityListener.
7) Actual application uses only single ApplicationContext where both persistence layer classes and web controllers are loaded in one single spring context.
8) Everything works fine when application runs. However when our integration test Runs the call appContext.getBean('userContextService') fails and throws NosuchBeanDefinitionException as it is unable to find the bean with name 'userContextService'
9) Now finally the code of our integration Test (only giving relevant details) which is located in com.mycompany.persistence.embeddeddb package:

  @Runwith(SpringJUnit4ClassRunner.class)
  @ConfigurationContext 
  class MyEntityTest{

        @Configuration
        @ComponentScan("com.mycompany.persistence")  
        public static class Config{
              .....
        }
        .....//code which eventually gives call to  
        AppDependencyHelper's method which in turn tries to retrieve userContextService Bean.
  }

Now the questions :
1) Why it fails to retrieve the bean? I have tried addingcom.mycompany.services like below

@ComponentScan({"com.mycompany.persistence","com.mycompany.services"})
but to no avail.
2) What I am able to understand by reading whatever I got is that @ContextConfiguration needs to be provided with either XML files or Annotated classes or WebApplicationInitializers(in my case as we are having only single ApplicationContext) to create an ApplicationContext from @Configuration classes. However I cannot do that as maven starts complaining about circular dependency which is rightly so as my @Service annotated class UserContextServiceImpl is in web-services module which is dependent on web-persistence module already where the test case class is written.
3) The only solution I can think of is moving all integrations test classes to web-services module so that I can tell @ConfigurationContext all the classes from which it should create an ApplicationContext.Am I right?

Last point : The ApplicationContext class is of type GenericApplciationContext when I run tests. When I run application its obviously AnnotatedEmbeddedWebApplicationContext

please let me know if there is any solution to this problem?

Shailesh Vaishampayan
  • 1,766
  • 5
  • 24
  • 52
  • Just to be sure: How's your class called, that implements `IUserContextService`? Did you stick with default bean naming conventions or did you give it an alternative bean name using `@Component(value = "userContextService")`? – Stefan Haberl Dec 21 '15 at 08:18
  • I feel like we are neglecting to refer to the correct sections of the Spring Manual in helping you to solve your problem.... by the same token this question is very large – Crowie Dec 23 '15 at 03:00

1 Answers1

1

From what I'm guessing you are trying to use a component from your web-service module in your integration tests. If that's the case, than yes, you should move your integration test cases to your web-service module - as you've already suggested in your question.

EDIT: You should really rethink your design, because you have a circular dependency problem here: Your web-service module depends on web-persistence, but the implementation of your IUserContextService in web-persistence is found in web-service.

You should probably move your IUserContextService (and all your integration tests) to your web-service package.

Stefan Haberl
  • 9,812
  • 7
  • 72
  • 81
  • Ok. great. But can you please tell me why it doesn't work even if I add the package of web-services in ComponentScan? If I add higher level package (com.mycompany), which contains other Component (and its friends ) classes, it gives different errors while the test initializes. But when I add my service package it initializes but breaks at runtime. Is ComponentScan ignoring it? – Shailesh Vaishampayan Dec 20 '15 at 21:25
  • 2
    Also even if hypothetically I solve this problem the problem of setting up SecurityContext still remains and the reason we have this problem is that we dont want to put Spring Security dependency in persistence module. So another reason to move this to web-services so that Spring Security can be enabled in my integration test correct? – Shailesh Vaishampayan Dec 20 '15 at 21:27
  • In regard to your first comment: Your test fails at initialization, when Spring cannot find an `@Autowire`d collaborator in your `@Component` classes. Your test fails at runtime, when you try to get a Bean from your fully built Spring container using `appContext.getBean('userContextService')` which simply does not exist – Stefan Haberl Dec 21 '15 at 08:16
  • Alright I was able to resolve this by adding an implementation class in persistence package which actually returned hard coded string. Not sure if this is right approach as this cannot be called a pure integration test. – Shailesh Vaishampayan Dec 21 '15 at 10:00
  • Make sure your `IUserContextService` stub sits in `src/test/java` – Stefan Haberl Dec 21 '15 at 10:13
  • No At runtime when actual application works as I have implementation in web-services module and we have only single application context. But for tests it doesn't scan web-services package. so introduced stub implementation in src/test/java in com.mycompany.persistence package which worked out. – Shailesh Vaishampayan Dec 21 '15 at 10:28