I want to test my orderService, each order has x cartItems, each cartItem is a product.
I managed to do some code, and thought I got it right, but encountered a problem :
java.lang.NullPointerException: Cannot invoke "com.proj.my.repository.OrderRepository.save(Object)" because "this.orderRepository" is null
at com.proj.my.service.impl.OrderServiceTest.testSaveOrder(OrderServiceTest.java:68)
at java.base/java.util.ArrayList.forEach(Unknown Source)
at java.base/java.util.ArrayList.forEach(Unknown Source)
How can it be null ??
I managed to do unit tests to my products, and to my users, but I can’t do it to my orders.
My order.java
package com.proj.my.model;
import java.time.LocalDate;
import java.util.List;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import lombok.ToString;
@ToString
@Entity
@Table(name = "myorder")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt"},
allowGetters = true)
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "userId")
private User user;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, targetEntity = ShoppingCart.class)
@JoinColumn(name = "order_id")
private List<ShoppingCart> cartItems;
@CreationTimestamp
@Column(updatable = false, name = "createdAt")
private LocalDate createdAt;
public LocalDate getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDate createdAt) {
this.createdAt = createdAt;
}
public Order() {
}
public Order(User user, LocalDate createdAt, List<ShoppingCart> cartItems) {
this.user = user;
this.cartItems = cartItems;
this.createdAt = createdAt;
}
public Order(int i, LocalDate now, List<ShoppingCart> cartItems2) {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setCustomer(User user) {
this.user = user;
}
public List<ShoppingCart> getCartItems() {
return cartItems;
}
public void setCartItems(List<ShoppingCart> cartItems) {
this.cartItems = cartItems;
}
}
My orderService.java
package com.proj.my.service;
import com.proj.my.model.Order;
import com.proj.my.model.CloudProduct;
import com.proj.my.model.ShoppingCart;
import com.proj.my.repository.OrderRepository;
import com.proj.my.repository.CloudProductRepository;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
@Service
public class OrderService {
private OrderRepository orderRepository;
private CloudProductRepository cloudProductRepository;
public OrderService(OrderRepository orderRepository, CloudProductRepository cloudProductRepository) {
this.orderRepository = orderRepository;
this.cloudProductRepository = cloudProductRepository;
}
public Order getOrderDetail(int orderId) {
Optional<Order> order = this.orderRepository.findById(orderId);
return order.isPresent() ? order.get() : null;
}
public List<Order> getAllOrderDetail(LocalDate yesterday, LocalDate today) {
today = LocalDate.now();
yesterday = today.minusDays(1);
return orderRepository.findAllByCreatedAtBetween(yesterday, today);
}
public float getCartAmount(List<ShoppingCart> shoppingCartList) {
float totalCartAmount = 0f;
float singleCartAmount = 0f;
for (ShoppingCart cart : shoppingCartList) {
String cloudProductName = cart.getProductName();
Optional<CloudProduct> product = cloudProductRepository.findByProductName(cloudProductName);
if (product.isPresent()) {
CloudProduct cloudproduct = product.get();
singleCartAmount = cart.getQuantity() * cloudproduct.getpriceInEuros();
totalCartAmount = totalCartAmount + singleCartAmount;
cart.setProductId(cloudproduct.getProductId());
cart.setAmount(singleCartAmount);
cloudProductRepository.save(cloudproduct);
}
}
return totalCartAmount;
}
public Order saveOrder(Order order) {
return orderRepository.save(order);
}
}
My orderController.java
package com.proj.my.controller;
import java.time.LocalDate;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.proj.my.dto.OrderDTO;
import com.proj.my.dto.ResponseOrderDTO;
import com.proj.my.model.Order;
import com.proj.my.model.User;
import com.proj.my.service.CloudProductService;
import com.proj.my.service.OrderService;
import com.proj.my.service.UserService;
@RestController
@RequestMapping("/api")
public class OrderController {
private OrderService orderService;
private CloudProductService cloudProductService;
private UserService userService;
public OrderController(OrderService orderService, CloudProductService cloudProductService, UserService userService) {
this.orderService = orderService;
this.cloudProductService = cloudProductService;
this.userService = userService;
}
@GetMapping(value = "/getOrder/{orderId}")
public ResponseEntity<Order> getOrderDetails(@PathVariable int orderId) {
Order order = orderService.getOrderDetail(orderId);
return ResponseEntity.ok(order);
}
@GetMapping(value = "/getOrder")
public List<Order> getAllOrderDetails(LocalDate yesterday, LocalDate today) {
return orderService.getAllOrderDetail(yesterday, today);
}
@PostMapping("/placeOrder")
public ResponseEntity<ResponseOrderDTO> placeOrder(@RequestBody OrderDTO orderDTO) {
ResponseOrderDTO responseOrderDTO = new ResponseOrderDTO();
float amount = orderService.getCartAmount(orderDTO.getCartItems());
User user = new User(orderDTO.getuserName(), orderDTO.getuserEmail());
Integer userIdFromDb = userService.isUserPresent(user);
if (userIdFromDb != null) {
user.setUserId(userIdFromDb);
}else{
user = userService.createUser(user);
}
LocalDate createdAt = LocalDate.now();
Order order = new Order(user, createdAt, orderDTO.getCartItems());
order = orderService.saveOrder(order);
responseOrderDTO.setAmount(amount);
responseOrderDTO.setDate(com.proj.my.util.DateUtil.getCurrentDateTime());
responseOrderDTO.setOrderId(order.getId());
return ResponseEntity.ok(responseOrderDTO);
}}
My orderRepository.java
package com.proj.my.repository;
import com.proj.my.model.Order;
import java.sql.Date;
import java.time.LocalDate;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface OrderRepository extends JpaRepository<Order,Integer> {
List<Order> findAllByCreatedAtBetween(LocalDate d1, LocalDate d2);
}
And finally, my orderServiceTest.java
package com.proj.my.service.impl;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import com.proj.my.model.CloudProduct;
import com.proj.my.model.Order;
import com.proj.my.model.ShoppingCart;
import com.proj.my.repository.CloudProductRepository;
import com.proj.my.repository.OrderRepository;
import com.proj.my.repository.ShoppingCartRepository;
import com.proj.my.service.OrderService;
import com.proj.my.service.CloudProductService;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
public class OrderServiceTest {
@Mock
private CloudProductRepository cloudProductRepository;
private CloudProductService cloudProductService;
private OrderRepository orderRepository;
private OrderService orderService;
Order order;
CloudProduct cloudProduct;
ShoppingCart shoppingCart;
private ShoppingCartRepository shoppingCartRepository;
AutoCloseable autoCloseable;
@BeforeEach
void setUp() {
autoCloseable = MockitoAnnotations.openMocks(this);
cloudProductService = new CloudProductServiceImpl(cloudProductRepository);
cloudProduct = new CloudProduct(1, "Maria", (float) 232);
orderService = new OrderService(orderRepository, cloudProductRepository);
shoppingCart = new ShoppingCart("Maria", 2);
List<ShoppingCart> cartItems = Arrays.asList(shoppingCart);
order = new Order(1, LocalDate.now(), cartItems);
}
@AfterEach
void tearDown() throws Exception {
autoCloseable.close();
}
@Test
void testSaveOrder(){
mock(CloudProduct.class);
mock(CloudProductRepository.class);
mock(Order.class);
mock(OrderRepository.class);
mock(ShoppingCart.class);
mock(ShoppingCartRepository.class);
when(orderRepository.save(order)).thenReturn(order); <----------Error here
assertThat(orderService.saveOrder(order)).isEqualTo(order);
}
}
I’m getting out of ideas, since I looked it up in the internet and I can’t find anything close to be similar. Maybe I’m just not paying the right attention.
2
Answers
In your
OrderService
class you are creating a privateOrderRepository
repository object however the object is null.You can resolve this problem by two of the following ways.
You can autowire your repository object
@Autowired
private OrderRepository orderRepository;
Or You can make your repository object
Final
private final OrderRepository orderRepository;
UPDATE
Add Lombok dependency to your maven
pom.xml
fileThen add
@RequiredArgsConstructor
and@AllArgsConstructor
to you service class. It should look like this. After these changes run your applicationTest setup is incorrectly using mockito.
Try: