Unable to use #DataJpaTest if Spring security is on classpath - java

I am trying to update my test cases to use the #DataJpaTest. However, I am encountering some issues that appear to be related to Spring Security. The following is an example of the test class.
#RunWith(SpringRunner.class)
#DataJpaTest
public class ExampleRepositoryTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
#Inject
private ExampleRepository repository;
#Test
public void test() throws Exception {
...
}
I keep getting the error java.lang.IllegalStateException: Failed to load ApplicationContext due to the missing bean org.springframework.security.config.annotation.ObjectPostProcessor.
The project is a RESTful application with Spring security. The original test case created a full Spring Boot context using #SpringBootTest. The #DataJpaTest is supposed to help me test the JPA slice, which is exactly what I want.
Any help would be greatly appreciated. What am I missing?

I got the same error.
for my case, I have added #SpringBootApplication and #EnableResourceServer on the same class.
when I move #EnableResourceServer to another configuration class, the error is gone.

Related

Spring Boot Integration test mock external dependency

I'm trying to create integration tests for my Spring Boot app. The idea is to launch an embedded postgres db and run http calls with TestRestTemplate to my controllers.
The problem is my project has a dependency we use for redis queues.
<dependency>
<groupId>com.github.sonus21</groupId>
<artifactId>rqueue-spring-boot-starter</artifactId>
<version>2.9.0-RELEASE</version>
</dependency>
I've tried to mock out the dependencies and most of them work, but with this one it complains I guess because it is a #Configuration not a #Component:
Dependency config class:
#Configuration
#AutoConfigureAfter({RedisAutoConfiguration.class})
#ComponentScan({"com.github.sonus21.rqueue.web", "com.github.sonus21.rqueue.dao"})
public class RqueueListenerAutoConfig extends RqueueListenerBaseConfig {
public RqueueListenerAutoConfig() {
}
...
}
My test config class
#TestConfiguration
public class TestRestTemplateConfig {
#Bean
#Primary
#Order(Ordered.HIGHEST_PRECEDENCE)
public RqueueListenerAutoConfig rqueueListenerAutoConfig() {
return Mockito.mock(RqueueListenerAutoConfig.class);
}
....
}
I've tried with #AutoConfigureOrder(1) at my config class but the original RqueueListenerAutoConfig launches before anything and my mocked beans haven't been declared yet.
To be honest mocking every service on that dependency is a pain, but I haven't figured out a way to mock the whole dependency with a single configuration. I tried not loading the dependency when I'm on the test profile but since it runs spring context my code needs it.
My test class has the following config:
#SpringBootTest
#Import(TestRestTemplateConfig.class)
#ActiveProfiles("test")
public class TestClass {
...
}
Any clues?
Thanks.
Try
#EnableAutoConfiguration(exclude=RqueueListenerAutoConfig.class)

Why is Spring #Autowired ApplicationContext null in integration test?

I'm still new to Spring and have looked at similar questions on stack but couldn't identify an answer from what I've read.
I'm receiving an NPE when I call my applicationContext variable, which means the bean must not have been created or injected correctly. Here is the relevant portion of my program.
#SpringBootTest
#ContextConfiguration(classes = TestConfig.class)
public class SampleIT {
#Autowired
private ApplicationContext applicationContext;
#Test
public void sampleMethod() throws Exception {
//NPE below
String[] allBeanNames = applicationContext.getBeanDefinitionNames();
//more logic
I'm trying to get the ApplicationContext instance to debug why other beans are null from my config, so this all must be because of a basic flaw in my understanding of how ApplicationContext is setup and beans from it are injected. Any help is very much appreciated!
Try to add the following annotation to your class SampleIT:
#RunWith(SpringRunner.class)
Answering my own question now. Importing org.junit.jupiter.api.Test instead of org.junit.Test will cause Junit5 to be used. This will allow Junit to work with Spring without the #RunWith(SpringRunner.class) annotation. There are still remnants of Junit4 left in the codebase I'm working in, so this is a quick fix before completely moving to Junit 5.
If you are using Junit in version 4, You have to use #RunWith(SpringRunner.class),
If you are using Junit version 5, You have to use #ExtendWith(SpringExtension.class).
Additionally if you are using Mockito You can use #ExtendWith(MockitoExtension.class) etc.
I highly recommend read documentation about #SpringBootTest annotation in this link
#SpringBootTest

Spring Boot Test #PreAuthorize in a Library Module

I have a library-module written using Spring Boot 1.5.21.
The library has a #Service with some methods annotated with #PreAutorize allowing only users with ADMIN authority to perform some actions, for example a delete.
Then I have a Spring Boot Application that uses that library. If I run the app and manually test it, it works. Only ADMINs can delete. I'd like to write test for it.
I was thinking in writing separate test for module and for the main app. In my module I can successfully unit test the operations. But I'm having troubles testing the #PreAuthotize, because the security context does not exist in the module, but in the main app. Is there a way to test that annotation in the module, and not in the main app?
The relevant code of my library:
#Service
public class MyService {
#PreAuthorize("hasAuthority('ADMIN')")
public void delete (long id){
.....
}
}
#RunWith(SpringRunner.class)
public class MyServiceTest {
private MyService service;
#Test
#WithAnonymousUser
public void deleteShouldFailIfAnonymous() {
... Verify exception thrown
}
#Test
#WithMockUser(authorities = 'USER')
public void deleteShouldFailIfNotAdmin() {
... Verify exception thrown
}
#Test
#WithMockUser(authorities = 'ADMIN')
public void deleteShouldPass() {
... Should pass
}
}
I've trying adding #EnableGlobalMethodSecurity(prePostEnabled = true) but with no luck. And as said, the SecurityConfiguration is loaded in the main app, it does not exist in the library-module.
Can I test the #PreAuthorize in the module or should I move it to the main app? I'd like to have it i the module if possible. Or maybe I can create a Context only for testing, but don't know how to do it.
Aspect-oriented features like #PreAuthorize are implemented as advice. Usually, this means that Spring will create a decorator interface that intercepts the method call, performs the advice (in this case, checking the condition and throwing an exception if it fails), and then sends the call on to the service object.
When you use new MyService, you're creating a bare object without the wrappers that implement the advice, so you won't see security, validation, caching, etc., applied. To see the behavior you want, you need to make your test bean #Autowired using the Spring test support.
You can use the MockMvc to test. This will help with module testing incase of integration testing.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class SecurityTests {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
}
#WithMockUser(roles="ADMIN")
#Test
public void withMockUser() {
mvc.perform(get("......"))
}
}

ContextConfiguration annotation exception

I have a pretty simple Spring Boot project that was just upgraded from Spring Boot 1.2.5.RELEASE to Spring Boot 1.3.0.M5 (which then relies on Spring 4.2.0.RELEASE), and now my project won't compile.
Project:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableEncryptableProperties
public class MyApp extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Test that fails compilation (my only test ATM):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {MyApp.class})
#DirtiesContext
public class MyDAO_DataTest {
#Autowired
MyDAO dao;
#Test
public void whenDoingAtest() throws Exception {
//...
}
}
When I try to compile, it fails on my test file, saying:
org.springframework.core.annotation.AnnotationConfigurationException: In AnnotationAttributes for annotation [org.springframework.test.context.ContextConfiguration] declared on [class com.example.MyDAO_DataTest], attribute [locations] and its alias [value] are declared with values of [{}] and [{class com.example.MyApp}], but only one declaration is permitted.
I found the feature that's the origin of the exception, but I don't really understand what I can do about it.
Update I "fixed" the issue by changing this line:
#SpringApplicationConfiguration(classes = {MyApp.class})
... to this:
#ContextConfiguration(classes = {MyApp.class},
loader = SpringApplicationContextLoader.class)
effectively working around the issue and allowing myself to work, but I don't understand why I had to. #SpringApplicationConfiguration is described as Similar to the standard ContextConfiguration but uses Spring Boot's SpringApplicationContextLoader, so what's the deal?
Spring Boot 1.3.0.M5 (which then relies on Spring 4.2.0.RELEASE)
That is unfortunately incorrect: Spring Boot 1.3.0.M5 depends explicitly on Spring Framework 4.2.1, not 4.2.0.
The exception you are seeing was addressed in Spring Framework 4.2.1, specifically in the following issues.
https://jira.spring.io/browse/SPR-13325
https://jira.spring.io/browse/SPR-13345
And changes made to #SpringApplicationConfiguration in Spring Boot 1.3.0 M5 require Spring Framework 4.2.1. See the following issue for details.
https://github.com/spring-projects/spring-boot/issues/3635
Thus, ensuring that you are running against Spring Framework 4.2.1 should resolve your problem.
Regards,
Sam

spring junit testing

I have a maven spring project (latest version) and I want to write some junit tests (latest version).
The issue I have is that my spring beans are autowired, and when I call them from junit test, I get null pointer exceptions, as spring doesn't autowire them.
How can I load the context so that things are autowired?
Have you studied Testing chapter in Spring reference documentation? Here is an example you should start with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTest {
#Resource
private FooService fooService;
// class body...
}
If you are in com.example.MyTest in /src/test/java, you will need /src/test/resources/com/example/MyTest-context.xml - but the exceptions will show you the way.
This is a possibility:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml"
// in the root of the classpath
#ContextConfiguration({"/applicationContext.xml"})
public class MyTest {
// class body...
}
Usually it's a good idea though to have a test-applicationContext for your test infrastructure.
You should use the SpringJUnit4ClassRunner on your test classes, and use #Resource (or #Autowired) on the field in your test class that contains the bean. You should consider having a special test context Spring configuration that uses stubs so that your tests are genuine unit tests, and don't rely on the whole application context.

Categories

Resources