[英]Spring Boot Testing Thymeleaf org.thymeleaf.exceptions.TemplateProcessingException
I am trying to test a controller but it always gives me the following Thymeleaf TemplateProcessingException:我正在尝试测试 controller 但它总是给我以下 Thymeleaf TemplateProcessingException:
org.springframework.web.util.NestedServletException: Request processing failed;
org.springframework.web.util.NestedServletException:请求处理失败; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "car.name" (template: "checkout" - line 56, col 35)
嵌套异常是 org.thymeleaf.exceptions.TemplateProcessingException:评估 SpringEL 表达式的异常:“car.name”(模板:“checkout” - 第 56 行,第 35 列)
This is my controller:这是我的 controller:
@Controller
public class BookingController {
@Autowired
private BookingService bookingService;
@Autowired
private UserService userService;
@Autowired
private BookingExtraService bookingExtraService;
@Autowired
private CarService carService;
@PostMapping("/checkout")
public String checkout(@RequestParam(required = false) List<Long> selectedExtras,
@RequestParam String userName,
@RequestParam String startAddress,
@RequestParam String goalAddress,
@RequestParam String dateOfTrip,
@RequestParam String timeOfTrip,
@RequestParam Integer numberOfPeople,
Model model,
HttpSession session){
session.setAttribute("userName", userName);
session.setAttribute("startAddress", startAddress);
session.setAttribute("goalAddress", goalAddress);
session.setAttribute("dateOfTrip", dateOfTrip);
session.setAttribute("timeOfTrip", timeOfTrip);
session.setAttribute("numberOfPeople", numberOfPeople);
List<BookingExtra> extras = new ArrayList<>();
if(selectedExtras != null) {
session.setAttribute("selectedExtras", selectedExtras);
for (Long extraId : selectedExtras) {
extras.add(bookingExtraService.findById(extraId));
}
}
model.addAttribute("extras", extras);
Car car = carService.findById((Long) session.getAttribute("selectedCar"));
model.addAttribute("car", car);
DecimalFormat df = new DecimalFormat("#0.00");
String priceTotalString = df.format(bookingService.calculatePrice(extras, car));
model.addAttribute("priceTotal", priceTotalString);
return "checkout";
}
This is my view "checkout":这是我的观点“结帐”:
<body>
<navbar th:insert="fragments.html :: navbar"></navbar>
<div class="div-gap"></div>
<div class="container">
<div class="container" style="width: 800px">
<h3>Zusammenfassung</h3>
<br>
<table class="table">
<thead>
<tr>
<th scope="col">Extra:</th>
<th scope="col">Preis:</th>
</tr>
</thead>
<tbody>
<tr th:if="${extras.empty}">
<td>keine Extras ausgewählt</td>
</tr>
<tr th:each="extra : ${extras}">
<td th:text="${extra.name}"></td>
<td th:text="${extra.price} + ' €'"></td>
</tr>
<tr>
<td>+ Grundpreis Auto
<span th:text="' (' +${car.name} + ')'"></span>
</td>
<td th:text="${car.basePrice} + ' €'"></td>
</tr>
<tr>
<td class="fs-4 fw-bold">Gesamt:</td>
<td class="fs-4 fw-bold" th:text="${priceTotal} + '€'"></td>
</tr>
</tbody>
</table>
<form th:action="@{/savebooking}" method="post">
<input type="hidden" name="dateOfTrip" th:value="${session.dateOfTrip}">
<input type="hidden" name="timeOfTrip" th:value="${session.timeOfTrip}">
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary fs-5 fw-bold">Buchen</button>
</div>
</form>
</div>
</div>
</body>
</html>
And this is my test class:这是我的测试 class:
@WebMvcTest(BookingController.class)
@AutoConfigureMockMvc(addFilters = false)
class BookingControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private BookingService bookingServiceMock;
@MockBean
private UserService userServiceMock;
@MockBean
private BookingExtraService bookingExtraServiceMock;
@MockBean
private CarService carServiceMock;
private static MockHttpServletRequest request;
@MockBean
private Car car;
@MockBean
private CarImage carImage;
@BeforeAll
public static void setup(){
request = new MockHttpServletRequest();
request.setParameter("userName", "test@test.de");
request.setParameter("startAddress", "Testaddress");
request.setParameter("goalAddress", "Testaddress");
request.setParameter("dateOfTrip", "2022/08/01");
request.setParameter("timeOfTrip", "08:00");
request.setParameter("numberOfPeople", "8");
}
@Test
public void shouldReturnCheckout() throws Exception{
when(carServiceMock.findById(1L)).thenReturn(car);
MvcResult mvcResult = this.mockMvc.perform(post("/checkout")
.contentType(MediaType.APPLICATION_JSON)
.param("userName", request.getParameter("userName"))
.param("startAddress", request.getParameter("startAddress"))
.param("goalAddress", request.getParameter("goalAddress"))
.param("dateOfTrip", request.getParameter("dateOfTrip"))
.param("timeOfTrip", request.getParameter("timeOfTrip"))
.param("numberOfPeople", request.getParameter("numberOfPeople")))
.andExpect(status().isOk()).andReturn();
ModelAndViewAssert.assertViewName(mvcResult.getModelAndView(), "checkout");
}
What I've already tried:我已经尝试过的:
Can anyone please point me in the right direction what I am missing here?谁能指出我在这里缺少的正确方向?
EDIT: Complete Stacktrace:编辑:完整的堆栈跟踪:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "car.name" (template: "checkout" - line 56, col 35)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:199)
at de.akad.web43.Controller.BookingControllerTest.shouldReturnCheckout(BookingControllerTest.java:124)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "car.name" (template: "checkout" - line 56, col 35)
at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292)
at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166)
at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109)
at org.thymeleaf.standard.expression.AdditionExpression.executeAddition(AdditionExpression.java:96)
at org.thymeleaf.standard.expression.ComplexExpression.executeComplex(ComplexExpression.java:62)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:112)
at org.thymeleaf.standard.expression.AdditionExpression.executeAddition(AdditionExpression.java:89)
at org.thymeleaf.standard.expression.ComplexExpression.executeComplex(ComplexExpression.java:62)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:112)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138)
at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144)
at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74)
at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95)
at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633)
at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314)
at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205)
at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136)
at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:661)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:366)
at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:190)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1401)
at org.springframework.test.web.servlet.TestDispatcherServlet.render(TestDispatcherServlet.java:137)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1145)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1084)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
... 78 more
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:51)
at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:406)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:92)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:112)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:338)
at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:265)
... 106 more
SOLUTION解决方案
Since自从
carServices.findId((Long) session.getAttribute("selectedCar")
needs the session attribute to return Car properly, I could resolve the issue by adding this attribute to the mocked session.需要 session 属性才能正确返回 Car,我可以通过将此属性添加到模拟的 session 来解决问题。 My adjusted test is as follows:
我调整后的测试如下:
@Test
public void shouldReturnCheckout() throws Exception{
when(carServiceMock.findById(1L)).thenReturn(car);
MvcResult mvcResult = this.mockMvc.perform(post("/checkout")
.contentType(MediaType.APPLICATION_JSON)
.param("userName", request.getParameter("userName"))
.param("startAddress", request.getParameter("startAddress"))
.param("goalAddress", request.getParameter("goalAddress"))
.param("dateOfTrip", request.getParameter("dateOfTrip"))
.param("timeOfTrip", request.getParameter("timeOfTrip"))
.param("numberOfPeople", request.getParameter("numberOfPeople"))
.sessionAttr("selectedCar", 1L))
.andExpect(status().isOk()).andReturn();
ModelAndViewAssert.assertViewName(mvcResult.getModelAndView(), "checkout");
}
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
原因:org.springframework.expression.spel.SpelEvaluationException:EL1007E:在 null 上找不到属性或字段“名称”
Meaning your car
object is returning as null mostly as a part of this call in BookingController
:这意味着您的
car
object 以 null 的形式返回,主要是作为BookingController
中此调用的一部分:
Car car = carService.findById((Long) session.getAttribute("selectedCar"));
Can you recheck if your carService
is returning any car object at all at this point.您能否重新检查一下您的
carService
是否在此时返回任何汽车 object。
If you managed to add proper non-null car
attribute to model, your issue will get resolved for "car.name" as well as for "car.basePrice".如果您设法将正确的非空
car
属性添加到 model,则“car.name”和“car.basePrice”的问题将得到解决。
If in some cases, car
used to return null, then you might need to use conditions something like this -如果在某些情况下,
car
曾经返回 null,那么您可能需要使用类似这样的条件 -
<div th:if= "${car!=null}">
//then access cars properties
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.