MockMVC instance not being instantiated - java

I am new to JUnit5 an MockMvc and am struggling to establish basic communication between a test class
and a Controller in a fully developed web application.
The UI is a Spring Boot application built on the MVC pattern. I would like to target one Controller
to prove my setup works and I have been using the MockMVC example in section 4.26.3 in the Spring Bott Reference
as a starting point (Spring Boot Reference)
When I run my test code I get the following a NullPointerException. Stepping through in debug mode shows me that
when I hit this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()) the mockMvc
instance is null. It would seem that there is an issue building MockMvc but does not provide any further information.
This is puzzling because the code is almost identical to the example provided:
#WebMvcTest([my controller class])
public class TestController {
#Autowired
private MockMvc mockMvc;
#MockBeans for Services
#Test
public void testConfig() {}
#Test
public void testGet() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk());
}
}
I am using version 5.7.1 of the junit jupiter engine. I am sorry I cannot post the whole pom as it is full of proprietory
information. I am also using Java 8 and Spring boot start test version 2.2.0.RELEASE.
I'd be very grateful for any suggestions as towhat I may have missed. Thanks.

Related

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("......"))
}
}

Should I test the main() method of Spring Boot Application and how?

When I create Spring Boot Application it generates 2 classes:
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
And the second on is test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class AppTest {
#Test
public void contextLoads() {
}
}
Like you can notice contextLoads test is empty. How should I provide correct test for contextLoad? It should stay empty maybe? Is it correct? Or I should put something inside?
UPDATE:
Why this test should stay? If I have more tests in application I'll know if spring context is loaded or nope. Isn't it just excessive.
I readed answers like this but it didn't gave me a clear answer.
Actually, the main() method of the Spring Boot Application is not covered by the unit/integration tests as the Spring Boot tests don't invoke the main() method to start the Spring Boot application.
Now I consider that all answers of this post seem overkill.
They want to add a test of the main() method to make a metric tool happy (Sonar).
Loading a Spring context and loading the application takes time.
Don't add it in each developer build just to win about 0.1% of coverage in your application.
I added an answer about that.
Beyond your simple example and the other post that you refer to, in absolute terms it may make sense to create a test for the main() method if you included some logic in. It is the case for example as you pass specific arguments to the application and that you handle them in the main() meethod.
Leave it empty. If an exception occurs while loading the application context the test will fail. This test is just saying "Will my application load without throwing an exception"
Update for Second Question
The reason you want to keep this test is that when something fails you want to find the root cause. If you application context is unable to load, you can assume all other tests that are failing are due to this. If the above test passes, you can assume that the failing tests are unrelated to loading the context.
When you build a Spring boot application using Spring Initializer. It auto creates Application and its Test Class
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#SpringBootTest
class ApplicationTest {
#Test
void contextLoads() {
}
}
Note the use of #SpringBootTest annotation on test class which tells Spring Boot to look for a main configuration class (one with #SpringBootApplication, for instance) and use that to start a Spring application context. Empty contextLoads() is a test to verify if the application is able to load Spring context successfully or not.
You do not need to provide any test cases for empty method as such. Though you can do something like this to verify your controller or service bean context:-
#SpringBootTest
public class ApplicationContextTest {
#Autowired
private MyController myController;
#Autowired
private MyService myService;
#Test
public void contextLoads() throws Exception {
assertThat(myController).isNotNull();
assertThat(myService).isNotNull();
}
}

Spring Boot - Test Cases - Dont Load All Components

I am trying to to rest my rest classes in Spring MVC
If I run the following code (ran fine when the project was small but now fails) it tries to load all the different components in my application.
This includes beans which interact with external systems and need credentials in order to connect
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class TestDummyRest extends BaseRestTestCase{
#Autowired
private MockMvc mockMvc;
#MockBean
private IDummyServices mockDummyServices;
#Test
public void getSendGoodMessage() throws Exception {
given(mockDummyServices.sendGoodMessage(Mockito.anyString())).willReturn(true);
mockMvc.perform(get("/dummy"))
.andExpect(status().isOk())
.andExpect(content().contentType(TEXT_PLAIN_CONTENT_TYPE));
verify(mockDummyServices, times(1)).sendGoodMessage(Mockito.anyString());
}
}
How do I tell my test classes not to load the #Configuration or #Component classes of my application?
Instead of not creating other classes in your application, you could only create the classes you are interested in, see 15.6.1 Server-Side Tests - Setup Options
The second is to simply create a controller instance manually without
loading Spring configuration. Instead basic default configuration,
roughly comparable to that of the MVC JavaConfig or the MVC namespace,
is automatically created and can be customized to a degree:
public class MyWebTests {
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
// ...
}
You need to use #TestComponent and #TestConfiguration for this as explained in Spring doc here

Unable to use #DataJpaTest if Spring security is on classpath

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.

Spring Boot and unit testing of controllers, can I read the value of #RequestMapping at runtime?

In a Java Spring Boot application, I define the controllers path in a dedicated properties file. e.g.
#PropertySource("classpath:/my.properties")
#RequestMapping("${controller1.path}")
public class Controller{
#RequestMapping("/dosomething")
public void doSomethingREST(){
}
}
where my.properties looks like:
controller1.path=rest/path
The path of the REST service will be then http://localhost:8080/rest/path/dosomething
How can I read the path in the unit test class?
Should I necessarily write it manually?
Suppose that I change it, doesn't seem to be a very flexible approach.
Suggestions to make it more dynamic?
As far as I know, there is no way to unit-test the value of an annotation, unless you would use reflection - but in that case you would in fact have written a "change detector", which is probably not what you want.
You could write an integration test however. The "Testing" chapter from the Spring Boot Reference Guide provides an introduction how you could integration test your application.
Basically, the procedure is as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#WebIntegrationTest
#SpringApplicationConfiguration(classes = SampleDataJpaApplication.class)
public class MyTest {
#Value("${local.server.port}")
int port;
RestTemplate template = new TestRestTemplate();
#Test
public void testRequest() throws Exception {
template.getForEntity("http://localhost:" + port + "/rest/path/dosomething", String.class);
// Somehow verify that your application did the right thing, e.g. because some mocked component was called or the system is in a certain state.
}
}

Categories

Resources