Home > Net >  Spring Boot Junit5: How to fix receiving 405 when testing GETMapping
Spring Boot Junit5: How to fix receiving 405 when testing GETMapping

Time:02-05

Im working on a Travel Blog project in Spring Boot and Im trying to do TDD. Im in the process of writing the tests for my BlogEntryController class which handles adding, deleting etc of BlogEntries.

BlogEntryControllerTest

package com.example.server;

import com.example.server.controller.BlogEntryController;
import com.example.server.models.user.BlogEntry;
import com.example.server.repositories.BlogEntryRepository;
import com.example.server.services.BlogEntryService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;


@WebMvcTest(controllers = BlogEntryControllerTest.class)
@ExtendWith(SpringExtension.class)
public class BlogEntryControllerTest {



    @TestConfiguration
    static class TravelEntryControllerTestConfiguration {
        @Autowired
        BlogEntryRepository blogEntryRepository;
        @Bean
        public BlogEntryService blogEntryService() {
            return new BlogEntryService(blogEntryRepository);
        }
    }

    private BlogEntryController blogEntryController;

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    BlogEntryService blogEntryService;

    @MockBean
    private BlogEntryRepository blogEntryRepository;

    @Autowired
    private ObjectMapper objectMapper;
    
    @Test
    void getAllBlogEntriesTest() throws Exception {
        BlogEntry blogEntry1 = new BlogEntry("Test title 1", "headerPictureSource 1", "This is the main content");
        BlogEntry blogEntry2 = new BlogEntry("Test title 2", "headerPictureSource 2 ", "content");
        
        List<BlogEntry> blogEntryList = Arrays.asList(blogEntry1, blogEntry2);
        Mockito.when(blogEntryService.getAllBlockEntries()).thenReturn(blogEntryList);

        mockMvc.perform(get("/blog/entries")).andExpect(status().is2xxSuccessful());

    }

}

BlogEntryController

package com.example.server.controller;

import com.example.server.models.user.BlogEntry;
import com.example.server.services.BlogEntryService;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
public class BlogEntryController {


    private final BlogEntryService blogEntryService;

    public BlogEntryController(BlogEntryService travelEntryService) {
        this.blogEntryService = travelEntryService;
    }


    @GetMapping("/blog/entries")
    public List<BlogEntry> getAllBlogEntries() throws Exception {
        return blogEntryService.getAllBlockEntries();
    }

}

BlogEntryService

package com.example.server.services;

import com.example.server.models.user.BlogEntry;
import com.example.server.repositories.BlogEntryRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BlogEntryService implements IBlogEntryService {
    private final BlogEntryRepository blogEntryRepository;

    public BlogEntryService(BlogEntryRepository travelEntryRepository) {
        this.blogEntryRepository = travelEntryRepository;
    }

    public List<BlogEntry> getAllBlockEntries() {
        return blogEntryRepository.findAll();
    }
}

BlogEntryRepository

package com.example.server.repositories;

import com.example.server.models.user.BlogEntry;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BlogEntryRepository extends JpaRepository<BlogEntry, Long> {
}

BlogEntry

package com.example.server.models.user;


import jakarta.annotation.Nullable;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.Objects;

@Entity
@Table(name = "blogEntries")
@NoArgsConstructor
public class BlogEntry {

    @Id
    @Getter
    @Setter
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "title")
    @Getter
    @Setter
    private String title;

    @Getter
    @Setter
    @Column(name = "headerPicture")
    private String headerPicture;

    @Getter
    @Setter
    @Column(name = "mainContent")
    private String mainContent;

    public BlogEntry(String title, String headerPicture, String mainContent) {
        this.title = title;
        this.headerPicture = headerPicture;
        this.mainContent = mainContent;
    }

    @Override
    public boolean equals(Object o) {

        if (this == o)
            return true;
        if (!(o instanceof BlogEntry))
            return false;
        BlogEntry blogEntry = (BlogEntry) o;
        return Objects.equals(this.id, blogEntry.id) && Objects.equals(this.title, blogEntry.title)
                && Objects.equals(this.headerPicture, blogEntry.headerPicture) && Objects.equals(this.mainContent, blogEntry.mainContent);
    }

    @Override
    public String toString() {
        return "BlogEntry{"   "id="   this.id   ", title='"   this.title   '\''   ", headerPicture='"   this.headerPicture   '\''   ", mainContent='"   this.mainContent   '\''   '}';
    }
}
MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /blog/entries
       Parameters = {}
          Headers = []
             Body = null
    Session Attrs = {}

Handler:
             Type = org.springframework.web.servlet.resource.ResourceHttpRequestHandler

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Range for response status value 404 expected:<SUCCESSFUL> but was:<CLIENT_ERROR>
Expected :SUCCESSFUL
Actual   :CLIENT_ERROR
<Click to see difference>

These are the involved classes.

My error output looks like this
I have already done the same for my User Entity so I figured I can write my Controllers, Services and tests and a similar fashion.

Im kinda out of expertise here. Any ideas?
Thanks a lot in advance

I have already tried to find a solution and checked various posts where HTTP requests methods were swapped (used post instead of get) or that I should use @ExtendWith or Mockmvc but obviously Im already doing that.

Also I noticed that most of those posts refer to problems when testing the POST method, however, here its the GET method.

I checked some suggested annotations on my controller method such as @ResponseBody or tried @RequestMapping with the respective params instead of @GetMapping.

I also checked wether my imports are correct and are the same as the once from my UserControllerTest cause Im basically doing the same stuff and there it all works.

Also note: My requests work in postman. So it seems as if its only a problem with the test itself, not the application.

CodePudding user response:

I think the following is incorrect

@WebMvcTest(controllers = BlogEntryControllerTest.class)

Should be:

@WebMvcTest(controllers = BlogEntryController.class)

There might be other issues after this change.

CodePudding user response:

The HTTP status code 405 (Method Not Allowed) indicates that the requested HTTP method is not supported for the requested resource. To fix this issue in a Spring Boot application with JUnit 5, you can check the following points:

Verify the HTTP method specified in the test: Ensure that you are using the correct HTTP method (e.g. GET, POST, PUT, DELETE, etc.) in the test method's @GetMapping or other appropriate annotation (e.g. @PostMapping).

Verify the URL path: Ensure that the URL path specified in the @GetMapping annotation matches the URL path of the endpoint being tested.

Disable CSRF protection: If your application has enabled CSRF protection, it may prevent you from making GET requests in tests. You can disable CSRF protection by adding the following to your test configuration class:

@TestConfiguration
public class TestConfig {
    @Bean
    public WebSecurityConfigurerAdapter securityConfigurerAdapter() {
        return new WebSecurityConfigurerAdapter() {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.csrf().disable();
            }
        };
    }
}
  • Related