0

NOTE: I fixed this question. See own answer :)

I have a unit test for testing different roles within spring security.

All the authentication and authorization is implemented and works through the user interface, but I can't seem to get it working in the unit test. This is my unit test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/test-context.xml"})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class UserServiceTest {

  @Autowired
  UserService userService;

  @Test
  public void UserNameAdminMustBeFound(){
    UserDetails userDetails = userService.loadUserByUsername("admin");
    assertEquals(userDetails.getUsername(), "admin");
  }

  @Test (expected = UsernameNotFoundException.class)
  public void UserNotFoundMustThrowException(){
    userService.loadUserByUsername("NotExistingUser");
  }

  @Test
  public void userWithAdminRoleHasAccessToTheMethod(){
    // admin has ADMIN_ROLE
    UserDetails userDetails = userService.loadUserByUsername ("admin");
    assertEquals("admin", userDetails.getPassword());
    this.dummyMethod();
  }

  @Test(expected = AccessDeniedException.class)
  public void userWithReadRoleHasNOAccessToTheMethod(){
    // viewer has VIEWER_ROLE (and thus no ADMIN_ROLE)
    UserDetails userDetails = userService.loadUserByUsername ("viewer");
    assertEquals("viewer", userDetails.getPassword());
    this.dummyMethod();
  }

  @PreAuthorize("hasRole('ADMIN_ROLE')")
  private void dummyMethod(){
      System.out.println("dummyMethod reached");
  }
}

If I comment out the last test 'userWithReadRoleHasNOAccessToTheMethod', everything works just fine. It is this last test that doesn't throw an exception AccessDeniedException. This is because I need the tag global-method-security pre-post-annotations="enabled" in my test-context.

However, and here it gets interesting, if I add this tag to my test-context.xml, I get a very different kind of error on ALL unit tests:

Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@43244fd9] to prepare test instance [com.sysunite.qms.services.UserServiceTest@4f651ff]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.sysunite.qms.services.UserServiceTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sysunite.ccy.pms.qms.security.UserService com.sysunite.qms.services.UserServiceTest.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sysunite.ccy.pms.qms.security.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sysunite.ccy.pms.qms.security.UserService com.sysunite.qms.services.UserServiceTest.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sysunite.ccy.pms.qms.security.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sysunite.ccy.pms.qms.security.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

It says I have not defined bean with id userService, however, it worked before, and it is clearly in my test-context.xml:

  <bean id="userService" class="com.sysunite.ccy.pms.qms.security.UserService">
    <property name="store" ref="quadStore"/>
    <property name="instanceService" ref="instanceService"/>
  </bean>

  <security:global-method-security pre-post-annotations="enabled"/>

Again, if i comment out the pre-post-annotations=enabled tag, everything works fine, but then I can't test the @preAuthorize annotation. Anyone has any idea how this is possible? It confuses me.

Thanks in advance!

Rens Groenveld
  • 960
  • 11
  • 28
  • Can you show the part of your test-context.xml where you declare `` ? See the answer here works for you. I'm not sure of what's going on, but I'm trying to help =) http://stackoverflow.com/questions/5403818/how-to-junit-tests-a-preauthorize-annotation-and-its-spring-el-specified-by-a-s – Gabriel Câmara Nov 06 '13 at 13:00
  • Hi Gabriel, thanks for the reply. I actually got it working now. See my own answer :) Thanks for the help though! the wasn't needed because that is actually an abstraction layer I do not test. (I test that through user interface) – Rens Groenveld Nov 06 '13 at 14:24

1 Answers1

0

Ok it took me a while but I finally got it working.

Basically there were 2 major mistakes that I made, one of that you as a reader of the problem could not see.

In my UserService class I had the following code:

  @Override
  @PreAuthorize("hasRole('ADMIN_ROLE')")
  public void deleteUser(String username) {
    // implementation of the method
  }

This caused some kind of dead lock causing Spring to give the Spring.NoSuchBeanDefinitionExceptionerror. I am not sure why, but somehow when Spring instantiates this class while the tag annotations = enabled is there, Spring can actually NOT instantiate the userService class.

My second mistake and new learning point: When using the @PreAuthorize annotation, always make sure that the class where it is located in, is instantiated by the spring context. In my case, I had the method within my own test class which was not instantiated by the spring context. It did have the @RunWith(SpringJUnit4ClassRunner.class) annotation, but apperently that's not doing it for Spring :)

Thanks for the help though :)

Rens Groenveld
  • 960
  • 11
  • 28