问题测试具有List属性的Bean。

huangapple go评论76阅读模式
英文:

Problem testing a Bean with a List property

问题

@Entity
public class Brand {
    
    @Id
    @GeneratedValue
    private Long id;
    
    @Column
    @NotNull(message = "Brand can not have empty name.")
    private String name;
    
    @Column
    private String description;
    
    @OneToMany(mappedBy="brand", cascade= {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)    
    @OrderBy("price ASC")
    private List<Product> productList;
   
    // getters and setters ...
}

@Entity
public class Product {
    
    @Id
    @GeneratedValue
    private Long id;
    
    @Column
    @NotNull(message = "Product can not have empty name.")
    private String name;
    
    @Column
    private Double price;
    
    @Column
    private Boolean onSale=false;
    
    @ManyToOne(cascade= {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinColumn(name="brand_id", nullable=false)
    private Brand brand;

    // getters and setters ...
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProductDTO {
    
    private Long id;
    
    private String name;    
    
    private Double price;    
    
    @JsonIgnore
    private Boolean onSale;
    
    private String event;
    
    // constructors, getters, and setters ...
}

public class BrandDTO {
    private String name;
    
    private List<ProductDTO> productList;
    
    // getters and setters ...
}

public interface BrandRepository extends JpaRepository<Brand, Long>{
    
    List<Brand> findAllByOrderByName();
}

public interface BrandService {

    List<Brand> getAllBrands();    
}

@Service
public class BrandServiceImpl implements BrandService {
    
    @Autowired
    BrandRepository myBrandRepo;
    
    @Override
    public List<Brand> getAllBrands(){
        return myBrandRepo.findAllByOrderByName();
    }    
}

public class ModelMapper {
    public static BrandDTO makeBrandDTO(Brand myBrand)
    {
        BrandDTO myBrandDTO=new BrandDTO();
        
        org.modelmapper.ModelMapper myStandardMapper=new org.modelmapper.ModelMapper();
        
        List<ProductDTO> myProductsList=myBrand.getProductList()
                .stream()
                .map(product->myStandardMapper.map(product, ProductDTO.class))
                .collect(Collectors.toList());
        myBrandDTO.setProductList(myProductsList);
        
        myBrandDTO.setName(myBrand.getName());
        
        return myBrandDTO;
    }
}

@RestController
@RequestMapping("v1/search")
public class BrandController {
    
    @Autowired
    BrandService myBrandService;
    
    @GetMapping("/get/products/")
    public Map<String, List<ProductDTO>> getAllProductsMap(){
        
        List<BrandDTO> myList= myBrandService.getAllBrands()
        .stream().map(brand->ModelMapper.makeBrandDTO(brand))
        .collect(Collectors.toList());        
        
        Map<String, List<ProductDTO>> myMap=new TreeMap<String, List<ProductDTO>> ();
        
        myList.forEach(brand->myMap.put(brand.getName(), brand.getProductList()));
        
        return myMap;
    }   
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProductApplication.class,webEnvironment=WebEnvironment.RANDOM_PORT)
public class ControllerLayerTester {
    
    private static Log myLogger = LogFactory.getLog(ControllerLayerTester.class);
    
    private static RestTemplate restTemplate;
    
    private static HttpHeaders headers;
    
    @LocalServerPort
    private int port;
    
    @BeforeClass
    public static void runBeforeAllTestMethods() {
     
        restTemplate = new RestTemplate();
        headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        
    }
    
    @Test
    public void testBrandListIsOrdered() {
        
        TreeMap<String, List<ProductDTO>> productList = restTemplate.getForObject("http://localhost:" + port + "/v1/search/get/products/", TreeMap.class);
        
        for (List<ProductDTO> myProductList : productList.values()) {
            myProductList.forEach(product -> assertTrue(product.getId() != null));
        }
    }
}

Please note that the provided code snippets are translations of the original code you provided, focusing solely on the code itself without any additional content.

英文:

Hi guys so here is my project:

Two entities connected with each other over a @OneToMany relationship:

@Entity
public class Brand {
@Id
@GeneratedValue
private Long id;
@Column
@NotNull(message = &quot;Brand can not have empty name.&quot;)
private String name;
@Column
private String description;
@OneToMany(mappedBy=&quot;brand&quot;
, cascade= {CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.PERSIST,
CascadeType.REFRESH},
fetch = FetchType.EAGER)	
@OrderBy(&quot;price ASC&quot;) // order products by price
private List&lt;Product&gt; productList;
// getters and setter following here ...
}
@Entity
public class Product {
@Id
@GeneratedValue
private Long id;
@Column
@NotNull(message = &quot;Product can not have empty name.&quot;)
private String name;
@Column
private Double price;
@Column
private Boolean onSale=false;
@ManyToOne(cascade= {CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.PERSIST,
CascadeType.REFRESH})
@JoinColumn(name=&quot;brand_id&quot;, nullable=false)
private Brand brand;
// getters and setter following here ...
}
package com.microservices.product.datatranferobject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProductDTO {
private Long id;
private String name;	
private Double price;	
@JsonIgnore // omit this property when exposing data over the API
private Boolean onSale;
private String event;
public ProductDTO() {
}    
public ProductDTO(Long id, String name, Double price, String event, Boolean onSale) {
super();
this.id = id;
this.name = name;
this.price = price;
this.event = event;
this.onSale=onSale;
}
public Boolean getOnSale() {
return onSale;
}
public void setOnSale(Boolean onSale) {
this.onSale = onSale;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getEvent() {
return onSale?&quot;ON SALE&quot;:null;
}
public void setEvent(String event) {
this.event = event;
}    
}
public class BrandDTO {
private String name;
private List&lt;ProductDTO&gt; productList;
public BrandDTO() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List&lt;ProductDTO&gt; getProductList() {
return productList;
}
public void setProductList(List&lt;ProductDTO&gt; productList) {
this.productList = productList;
}	
}

A simple DAO Class:

public interface BrandRepository extends JpaRepository&lt;Brand, Long&gt;{
List&lt;Brand&gt; findAllByOrderByName();
}

A simple service:

public interface BrandService {
List&lt;Brand&gt; getAllBrands();	
}
@Service
public class BrandServiceImpl implements BrandService {
@Autowired
BrandRepository myBrandRepo;
@Override
public List&lt;Brand&gt; getAllBrands(){
return myBrandRepo.findAllByOrderByName();
}	
}

and a controller which maps Products to ProductDTOs usinf my custom programmed Mapper:

public class ModelMapper {
public static BrandDTO makeBrandDTO(Brand myBrand)
{
BrandDTO myBrandDTO=new BrandDTO();
org.modelmapper.ModelMapper myStandardMapper=new org.modelmapper.ModelMapper();
List&lt;ProductDTO&gt; myProductsList=myBrand.getProductList()
.stream()
.map(product-&gt;myStandardMapper.map(product, ProductDTO.class))
.collect(Collectors.toList());
myBrandDTO.setProductList(myProductsList);
myBrandDTO.setName(myBrand.getName());
return myBrandDTO;
}
}
@RestController
@RequestMapping(&quot;v1/search&quot;)
public class BrandController {
@Autowired
BrandService myBrandService;
@GetMapping(&quot;/get/products/&quot;)
public Map&lt;String, List&lt;ProductDTO&gt;&gt; getAllProductsMap(){
List&lt;BrandDTO&gt; myList= myBrandService.getAllBrands()
.stream().map(brand-&gt;ModelMapper.makeBrandDTO(brand))
.collect(Collectors.toList());		
Map&lt;String, List&lt;ProductDTO&gt;&gt; myMap=new TreeMap&lt;String, List&lt;ProductDTO&gt;&gt; ();
myList.forEach(brand-&gt;myMap.put(brand.getName(), brand.getProductList()));
return myMap;
}
}

ProductDTO is quite the same as Product entity so I will spare the time ans space writing it down.

So here comes the Problem. I am using Junit to test my Controller having the following class run the test:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProductApplication.class,webEnvironment=WebEnvironment.RANDOM_PORT)
public class ControllerLayerTester {
private static Log myLogger = LogFactory.getLog(ControllerLayerTester.class);
private static RestTemplate restTemplate;
private static HttpHeaders headers;
@LocalServerPort
private int port;
@BeforeClass
public static void runBeforeAllTestMethods() {
restTemplate = new RestTemplate();
headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
}
/**
* simple test to verify the given requirements
*/
@Test
public void testBrandListIsOrdered() {
TreeMap&lt;String, List&lt;ProductDTO&gt;&gt; productList=restTemplate.getForObject(&quot;http://localhost:&quot;+port+&quot;/v1/search/get/products/&quot;,TreeMap.class);
for (List&lt;ProductDTO&gt; myProductList:productList.values()) {
myProductList.forEach(product-&gt;assertTrue(product.getId()!=null));
}
}
}

And when I run it I get the following error:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.microservices.product.datatranferobject.ProductDTO
at java.util.ArrayList.forEach(ArrayList.java:1257)
at com.microservices.product.ControllerLayerTester.testBrandListIsOrdered(ControllerLayerTester.java:81)

Am I doing something wrong here ? Why am I not getting the List filled with my entities but instead filled with LinkedHashMaps? Is there a solution in order to get a List of Products?

EDIT:

I am also providing here my project dependencies and I added on top of my post also the DTOs:

buildscript {
ext {
springBootVersion = &#39;2.1.0.RELEASE&#39;
}
repositories {
mavenCentral()
}
dependencies {
classpath(&quot;org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}&quot;)
}
}
apply plugin: &#39;java&#39;
apply plugin: &#39;eclipse&#39;
apply plugin: &#39;org.springframework.boot&#39;
apply plugin: &#39;io.spring.dependency-management&#39;
group = &#39;com.microservices&#39;
version = &#39;0.0.1-SNAPSHOT&#39;
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation(&#39;org.springframework.boot:spring-boot-starter-data-jpa&#39;)
implementation(&#39;org.springframework.boot:spring-boot-starter-web&#39;)
compile(&quot;org.springframework.boot:spring-boot-devtools&quot;)
compile group: &#39;org.modelmapper&#39;, name: &#39;modelmapper&#39;, version: &#39;2.1.0&#39;
runtimeOnly(&#39;com.h2database:h2&#39;)
testImplementation(&#39;org.springframework.boot:spring-boot-starter-test&#39;)
testImplementation &#39;org.assertj:assertj-core:3.15.0&#39;
compile group: &#39;com.google.guava&#39;, name: &#39;guava&#39;, version: &#39;23.5-jre&#39;
compile group: &#39;io.springfox&#39;, name: &#39;springfox-swagger2&#39;, version: &#39;2.7.0&#39;
compile group: &#39;io.springfox&#39;, name: &#39;springfox-swagger-ui&#39;, version: &#39;2.7.0&#39; 
}

答案1

得分: 1

问题在于无法从TreeMap.class推断出对TreeMap&lt;String, List&lt;ProductDTO&gt;&gt;的参数化,而这是在restTemplate.getForObject(...)中发生的。

您应该使用更通用的版本:

restTemplate.exchange(
    "http://localhost:" + port + "/v1/search/get/products/",
    HttpMethod.GET,
    new HttpEntity<>(null, headers),
    new ParameterizedTypeReference<TreeMap<String, List<ProductDTO>>>() {}
)
英文:

The problem is that parameterization of TreeMap&lt;String, List&lt;ProductDTO&gt;&gt; cannot be inferred from TreeMap.class inside restTemplate.getForObject(...)

You'll want to use the more generic version:

restTemplate.exchange(
&quot;http://localhost:&quot;+port+&quot;/v1/search/get/products/&quot;,
HttpMethod.GET,
new HttpEntity&lt;&gt;(null, headers),
new ParameterizedTypeReference&lt;TreeMap&lt;String, List&lt;ProductDTO&gt;&gt;() {}
)

huangapple
  • 本文由 发表于 2020年3月17日 03:26:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/60712103.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定