RestController POST方法的Spring Boot单元测试预期:201实际:400

时间:2018-06-20 13:04:57

标签: spring junit mockmvc

我正在尝试为RestController设置单元测试,但是对于post方法,我总是获取状态400而不是201。我看不出有什么问题。 其余服务使用curl可以正常工作。另外,传递的JSON与传递给原始服务的JSON相同,但是以某种方式我的单元测试无法正常工作。

我得到的错误:

java.lang.AssertionError: Status 
Expected :201
Actual   :400
 <Click to see difference>


    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:55)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:82)
    at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:617)
    at org.springframework.test.web.servlet.result.StatusResultMatchers$$Lambda$635/569974522.match(Unknown Source)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:178)
    at eu.devroyal.bosstools.service.TimesheetRequestControllerTest.createTimesheet(TimesheetRequestControllerTest.java:150)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

实体:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.persistence.*;
import java.sql.Time;
import java.util.Date;

@Entity
public class Timesheet {

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

    @Temporal(TemporalType.DATE)
    private Date date;

    @Temporal(TemporalType.TIME)
    @JsonFormat(pattern = "HH:mm:ss")
    @JsonDeserialize(using = SqlTimeDeserializer.class)
    private Date startTime;
    @Temporal(TemporalType.TIME)
    @JsonFormat(pattern = "HH:mm:ss")
    @JsonDeserialize(using = SqlTimeDeserializer.class)
    private Date endTime;

    private double pause;

    private double invoicedTime;

    private String description;

    @ManyToOne
    private Customer customer;

    public Timesheet() {
    }

    public Timesheet(Date date, Date startTime, Date endTime, double pause, double invoicedTime, String description, Customer customer) {
        this.date = date;
        this.startTime = startTime;
        this.endTime = endTime;
        this.pause = pause;
        this.invoicedTime = invoicedTime;
        this.description = description;
        this.customer = customer;

    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Time startTime) {
        this.startTime = startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Time endTime) {
        this.endTime = endTime;
    }

    public double getPause() {
        return pause;
    }

    public void setPause(double pause) {
        this.pause = pause;
    }

    public double getInvoicedTime() {
        return invoicedTime;
    }

    public void setInvoicedTime(double invoicedTime) {
        this.invoicedTime = invoicedTime;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

RestController中的方法:

  @PostMapping("/timesheets")
    public ResponseEntity<Object> createTimesheetEntry(@RequestBody Timesheet timesheet) {

        Timesheet savedTimesheet = timeRepo.save(timesheet);

        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
                .buildAndExpand(savedTimesheet.getId()).toUri();

        return ResponseEntity.created(location).build();
    }

在这里,我的单元测试方法createTimeSheet无法正常工作。

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.hamcrest.Matchers.*;


import org.springframework.web.context.WebApplicationContext;

import java.io.IOException;
import java.nio.charset.Charset;

import org.springframework.test.web.servlet.setup.MockMvcBuilders;;
import org.springframework.web.context.WebApplicationContext;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;


@RunWith(SpringRunner.class)
@SpringBootTest()
@WebAppConfiguration
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class TimesheetRequestControllerTest {

    private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(),
            Charset.forName("utf8"));


    private MockMvc mockMvc;

    private List<Timesheet> timesheetList;

    private Customer customer;


    private HttpMessageConverter mappingJackson2HttpMessageConverter;


    @Autowired
    private TimesheetRepository timeRepo;

    @Autowired
    private CustomerRepository customerRepo;

    @Autowired
    private WebApplicationContext webApplicationContext;


    @Autowired
    void setConverters(HttpMessageConverter<?>[] converters) {

        this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream()
                .filter(hmc -> hmc instanceof MappingJackson2HttpMessageConverter)
                .findAny()
                .orElse(null);

        assertNotNull("the JSON message converter must not be null",
                this.mappingJackson2HttpMessageConverter);
    }

    @Before
    public void setup() throws Exception {

        timesheetList = new ArrayList<>();
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();

        customer = customerRepo.save(new Customer("New Customer", 666L));
        timesheetList.add(timeRepo.save(new Timesheet(new Date(), new Date(), new Date(), 1.5, 8.0, "Some work", customer)));
        timesheetList.add(timeRepo.save(new Timesheet(new Date(), new Date(), new Date(), 1.5, 8.0, "Some work", customer)));

    }

    @Test
    public void userNotFound() throws Exception {
       /* mockMvc.perform(post("/george/bookmarks/")
                .content(this.json(new Bookmark(null, null, null)))
                .contentType(contentType))
                .andExpect(status().isNotFound());

                */
    }

    @Test
    public void readSingleTimesheetEntry() throws Exception {
        mockMvc.perform(get("/timesheets/"
                + this.timesheetList.get(0).getId()))
                .andExpect(status().isOk())
                .andExpect(content().contentType(contentType))
                .andExpect(jsonPath("$.id", is(this.timesheetList.get(0).getId().intValue())));

        //        .andExpect(jsonPath("$.uri", is("http://bookmark.com/1/" + userName)))
        //        .andExpect(jsonPath("$.description", is("A description")));

    }

    @Test
    public void readTimesheets() throws Exception {
         mockMvc.perform(get( "/timesheets"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(contentType))
                .andExpect(jsonPath("$", hasSize(2)))
                .andExpect(jsonPath("$[0].id", is(this.timesheetList.get(0).getId().intValue())))
                //.andExpect(jsonPath("$[0].uri", is("http://bookmark.com/1/" + userName)))
                //.andExpect(jsonPath("$[0].description", is("A description")))
                .andExpect(jsonPath("$[1].id", is(this.timesheetList.get(1).getId().intValue())));
                //.andExpect(jsonPath("$[1].uri", is("http://bookmark.com/2/" + userName)))
                //.andExpect(jsonPath("$[1].description", is("A description")));

    }

    @Test
    public void createTimesheet() throws Exception {
        String timeSheetJSON = json(new Timesheet(new Date(), new Date(), new Date(), 1.5, 8.0, "Some work", this.customer));

        //String timeSheetJSOn = "{\"id\“:null,\“date\":\"2018-06-20\",\"startTime\":\"09:52:47\",\"endTime\":\"09:52:47\",\"pause":0.5,\"invoicedTime\":7.75,\"description\":\"Change implemented XYZ\",\"customer":{\"id\":3,"name":\"Customer 3",\"customerNumber":666666}}";

        this.mockMvc.perform(post("/timesheets")
                .contentType(contentType)
                .content(timeSheetJSON))
                .andExpect(status().isCreated());
    }

    protected String json(Object o) throws IOException {
        MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
        this.mappingJackson2HttpMessageConverter.write(
                o, MediaType.APPLICATION_JSON, mockHttpOutputMessage);
        return mockHttpOutputMessage.getBodyAsString();
    }


}

1 个答案:

答案 0 :(得分:1)

所以我找到了解决方法:

我从时间表实体中删除了@JsonDeserialize(使用= SqlTimeDeserializer.class)批注,现在我的单元测试成功了,并且我收到HTTP状态201。 我并没有真正了解它,但是现在它可以了。感谢您的帮助和建议,以检查生成的JSON。

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.persistence.*;
import java.sql.Time;
import java.util.Date;

@Entity
public class Timesheet {

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

    @Temporal(TemporalType.DATE)
    private Date date;

    @Temporal(TemporalType.TIME)
    @JsonFormat(pattern = "HH:mm:ss")
    private Date startTime;
    @Temporal(TemporalType.TIME)
    @JsonFormat(pattern = "HH:mm:ss")
    private Date endTime;

    private double pause;

    private double invoicedTime;

    private String description;

    @ManyToOne
    private Customer customer;

    public Timesheet() {
    }

    public Timesheet(Date date, Date startTime, Date endTime, double pause, double invoicedTime, String description, Customer customer) {
        this.date = date;
        this.startTime = startTime;
        this.endTime = endTime;
        this.pause = pause;
        this.invoicedTime = invoicedTime;
        this.description = description;
        this.customer = customer;

    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Time startTime) {
        this.startTime = startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Time endTime) {
        this.endTime = endTime;
    }

    public double getPause() {
        return pause;
    }

    public void setPause(double pause) {
        this.pause = pause;
    }

    public double getInvoicedTime() {
        return invoicedTime;
    }

    public void setInvoicedTime(double invoicedTime) {
        this.invoicedTime = invoicedTime;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}