简体   繁体   中英

Problem with status 415 in Spring MockMVC Tests after trying to send a REST Post Request

I have a REST POST endpoint which is used to create an entity. I've trying to test it with MockMVC but every time that i sent the request i received a 415 status code (media not supported): java.lang.AssertionError: Status expected:<201> but was:<415> Expected:201 Actual:415

The endpoint accepts json body in the request and I sent this data using the MockMVC contentType as APPLICATION_JSON_VALUE and the content method with the serialized object by Jackson.

The controller ALSO is managed my Spring Security Filters but i think this is not the problem as i'm using the @AutoConfigureMockMvc(addFilters = false) and the HTTP status code is related to not supported media type and not about any security exception.

I've found a plenty of topics talking about it but none was able to solve my problem. One of the cases was including the @EnableWebMvc into the Controller OR as a configuration bean test, but none work it.

My attempt with @EnableWebMvc as test bean

@TestConfiguration
@EnableWebMvc
public class ProdutoControllerConfigurationTest {
    @Bean
    public ProdutoController produtoController() {
        return new ProdutoController(/* dependencies by autowired */);
    }
}

EDIT: I also tried with different MediaType like MediaType.APPLICATION_JSON and MediaType.APPLICATION_JSON_VALUE

My DTO class

public class CriarProdutoDTO {
    @NotNull
    @Size(min = 2)
    @JsonProperty("nome_produto")
    private final String nomeProduto;

    @DecimalMin("0.1")
    private final BigDecimal preco;
    private final String descricao;

    @NotNull
    @Min(0)
    @JsonProperty("quantidade_estoque")
    private final Integer quantidadeEstoque;

    @NotNull
    @Min(1)
    @JsonProperty("categoria_id")
    private final Integer categoriaId;

    public CriarProdutoDTO(String nomeProduto, BigDecimal preco, String descricao, Integer quantidadeEstoque, Integer categoriaId) {
        this.nomeProduto = nomeProduto;
        this.preco = preco;
        this.descricao = descricao;
        this.quantidadeEstoque = quantidadeEstoque;
        this.categoriaId = categoriaId;
    }
}

My current tests:

@ActiveProfiles("testes")
@ExtendWith(SpringExtension.class)
@SpringBootTest
@WebAppConfiguration
@AutoConfigureMockMvc(addFilters = false)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY)
public class ProdutoControllerTest {

    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void deveRetornarCreated_criacaoProdutoSucesso() throws Exception {
        CriarProdutoDTO criarProdutoDTO = new CriarProdutoDTO("Nome", new BigDecimal("2.0"), "DESCRIÇÃO", 2, 1);

        mockMvc.perform(MockMvcRequestBuilders.post("/api/produtos")
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(objectMapper.writeValueAsString(criarProdutoDTO)))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isCreated());
    }

}

My Controller:

@RestController
@RequestMapping(value = "/api/produtos")
public class ProdutoController {

    @Autowired
    private ProdutoService produtoService;
    @Autowired
    private CriarProdutoDtoToProdutoConverter produtoConverter;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void cadastrar(@RequestBody @Valid CriarProdutoDTO produtoDTO) {
        Produto novoProduto = produtoConverter.converter(produtoDTO);
        produtoService.cadastrar(novoProduto);
    }
}

try add Accept header to your request

Accept=application/json

I found out the problem. The problem was occurring in Jackson's Serialization from my Data Transfer Object (DTO)

My DTO has an args-constructor and because of that i have to use the @JsonCreator to point the args constructor. What i didn't expect was that you must annotate all the constructor parameters with @JsonProperty as Jackson didn't know the exact order to instantiate the object from the construtor, that was my problem.

Another way is creating a bean for that, so you don't have to use the @JsonCreator

The solution:

@JsonCreator
public CriarProdutoDTO(
        @JsonProperty("nome_produto") String nomeProduto, @JsonProperty("preco") BigDecimal preco,
        @JsonProperty("descricao") String descricao, @JsonProperty("quantidade_estoque") Integer quantidadeEstoque,
        @JsonProperty("categoria_id") Integer categoriaId) {
    this.nomeProduto = nomeProduto;
    this.preco = preco;
    this.descricao = descricao;
    this.quantidadeEstoque = quantidadeEstoque;
    this.categoriaId = categoriaId;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM