Spring Boot Testing Thymeleaf org.thymeleaf.exceptions.TemplateProcessingException

therealkon

I am trying to test a controller but it always gives me the following Thymeleaf TemplateProcessingException:

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)

This is my 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:

@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", "[email protected]");
        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:

  • Setting Expectations for car.name and car.getname() with when().thenReturn()
  • Loading the whole ApplicationContext with @SpringBootTest and instead of @WebMvcTest
  • Creating a new Car instance and returning it with thenReturn() instead of the mocked Car instance
  • Searching the internet for 2 days for a possible solution

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. 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");
}
Ashish Patil

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null

Meaning your car object is returning as null mostly as a part of this call in 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.

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".

If in some cases, car used to return null, then you might need to use conditions something like this -

 <div th:if= "${car!=null}">
  //then access cars properties

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Spring Boot 1.4 MVC testing with Thymeleaf results in TemplateProcessingException

org.thymeleaf.exceptions.TemplateProcessingException: Concatenation href

Spring Thymeleaf TemplateProcessingException in SpringInputGeneralFieldTagProcessor

org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "ServiceAmc.id" (results:30)

org.thymeleaf.exceptions.TemplateProcessingException: Only variable expressions returning numbers or booleans are allowed in this context

Thymeleaf exceptions for resolving template in spring boot

My spring-boot app gives the following error "org.thymeleaf.exceptions.TemplateInputException:"

Thymeleaf : org.thymeleaf.exceptions.TemplateInputException

Thymeleaf: org.thymeleaf.exceptions.TemplateInputException

Spring Boot - Thymeleaf template

spring boot and thymeleaf

Pagination with Spring Boot and Thymeleaf

Spring Boot, Thymeleaf and @Controller

Spring Boot, Thymeleaf and CSS

Issues with Spring Boot and Thymeleaf

thymeleaf caching with spring boot

Thymeleaf dropdown with Spring Boot

Spring Boot + Thymeleaf ERROR java.lang.ClassNotFoundException: org.thymeleaf.dom.Attribute

Spring Boot & Thymeleaf: list of links

Spring Boot & Thymeleaf: list of links

Spring Boot & Thymeleaf with XML Templates

Spring boot thymeleaf display of productName

Spring Boot Thymeleaf Dropdown List

Spring Boot - Thymeleaf and Json Templates

Spring Boot with thymeleaf method not calling

@WebAppConfiguration and @ContextConfiguration for Spring Boot + Thymeleaf

spring boot Thymeleaf relative urls

Spring Boot Thymeleaf Ajax Call

Spring boot with Thymeleaf 3 Beta