我正在尝试为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();
}
}
答案 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);
}
}