6

In a Spring Boot application I want to test (JUnit 5) the persistence layer with enabled auditing (@EnableJpaAuditing). I use Liquibase to setup a H2 db and Hibernate as the JPA implementation.

@Configuration
//@EnableTransactionManagement
@EnableJpaAuditing
//@EnableJpaRepositories
public class MyPersistenceConfig {
}

My entity has the following fields:

@CreatedDate
@Column(name = "CREATED_AT", updatable = false)
private Instant createdAt;

@CreatedBy
@Column(name = "CREATED_BY", updatable = false)
private String createdBy;

@CreatedDate
@Column(name = "LAST_MODIFIED_AT")
private Instant lastModifiedAt;

@CreatedBy
@Column(name = "LAST_MODIFIED_BY")
private String lastModifiedBy;

I have the following dependencies:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-core</artifactId>
        <scope>runtime</scope>
        <!--<scope>test</scope>-->
    </dependency>

    <!-- Testing -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
    </dependency>

I tried several combinations of annotations:

@SpringBootTest //(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//@DataJpaTest
@ContextConfiguration(classes = MyPersistenceConfig.class)
@EnableAutoConfiguration
//@SecurityTestExecutionListeners
//@Import(SpringBootWebSecurityConfiguration.class)
@WithMockUser(username = "test", password = "test", roles = "USER")
@ExtendWith(SpringExtension.class)
class MyRepositoryTest {

    @Autowired
    private MyRepository testee;

...
}

But whatever I try, either the repository is null (autowiring) or I get an exception when inserting an entry:

NULL not allowed for column "CREATED_BY"; SQL statement:

I guess I need a SecurityContext (which isn't available for autowiring currently).

What is the easiest way to provide a mock SecurityContext that works with auditing and @WithMockUser?

Puce
  • 37,247
  • 13
  • 80
  • 152
  • `@WithMockUser` mocks a `SecurityContext` with `UsernamePasswordAuthenticationToken` as the principal. I'm not sure why you are getting the `NULL now allowed...` error. Are you able to share your sample via a GitHub repo? – Joe Grandja Mar 19 '19 at 16:06

2 Answers2

1

This is an old question but for those who may stumble upon it trying to get Spring Data auditing to work in their integration tests this may help. The auditing functionality requires an AuditingAware bean to get the current user. In DataJpaTest this seems to be missing. One way to make it available is adding a @Bean configuration to your test.

@RunWith(SpringRunner.class)
@DataJpaTest
@Import({DatabaseIntegrationTest.TestConfig.class})
@WithMockUser
class DatabaseIntegrationTest {

  @TestConfiguration
  static class TestConfig {
    @Bean
    public AuditorAware<String> auditorAware() {
      return () -> Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication().getName());
    }
  }
}
Toni
  • 3,296
  • 2
  • 13
  • 34
Mustafa
  • 5,624
  • 3
  • 24
  • 40
-1
@Before
public void setup() {

    User user = userService.findByEmail("umanking@gmail.com").get();

    SecurityContextHolder.getContext().setAuthentication(new Authentication() {
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return null;
        }

        @Override
        public Object getCredentials() {
            return user.getPassword();
        }

        @Override
        public Object getDetails() {
            return user;
        }

        @Override
        public Object getPrincipal() {
            return null;
        }

        @Override
        public boolean isAuthenticated() {
            return true;
        }

        @Override
        public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

        }

        @Override
        public String getName() {
            return user.getName();
        }
    });

}

maybe you can use @Before annotation

andrew
  • 1
  • 1