I have a class which adds features to categories of products in the same category and prices based on the productCode of the product. I have a List of List of products in the same category and productCode for which the same price and category should be added. However, when I create a mock for the ProductDecorator it fails to return any products. I am using Lombok's @EqualsAndHashCode.Include on productCode in both classes
Here is the code
public class ProductDetail {
String productCode;
String category;
Double price;
public String getProductCode() {
return productCode;
}
}
class Product {
String name;
String productCode;
String category;
Double price;
String getProductCode() {
return productCode;
}
public Product addDetail(String category, Double price) {
this.category = category;
this.price = price;
return this;
}
}
public class ProductDecorator {
List<Product> addProductFeature(List<Product> products, List<ProductDetail> details) {
List<Product> productList = new ArrayList<>();
products.forEach(product -> {
details.forEach(detail -> {
if (product.getProductCode().equals(detail.getProductCode())) {
Product p = product.addDetail(detail.category, detail.price);
productList.add(p);
}
});
});
return productList;
}
}
// 3 Products and 3 product details objects that match
List<List<Product>> products = getProducts()
List<ProductDetail> productDetailList = getProductDetails()
ProductDecorator productDecorator = Mock()
// Returns null all the time for all, just showing the first one
productDecorator.addProductFeature(products[0],productDetailList)>>[products[0]]
How do I successfully mock the decorator to match. I think it is not matching because of some equality issues.I tried using underscores but that did not work either. I'd be grateful for a solution to thsi problem
For me, it works like this, so probably your original code looks different:
package de.scrum_master.stackoverflow.q77412076;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@EqualsAndHashCode
@ToString
public class ProductDetail {
String productCode;
String category;
Double price;
String getProductCode() {
return productCode;
}
}
package de.scrum_master.stackoverflow.q77412076;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@EqualsAndHashCode
@ToString
public class Product {
String name;
String productCode;
String category;
Double price;
String getProductCode() {
return productCode;
}
Product addDetail(String category, Double price) {
this.category = category;
this.price = price;
return this;
}
}
package de.scrum_master.stackoverflow.q77412076;
import java.util.ArrayList;
import java.util.List;
public class ProductDecorator {
List<Product> addProductFeature(List<Product> products, List<ProductDetail> details) {
List<Product> productList = new ArrayList<>();
products.forEach(product -> {
details.forEach(detail -> {
if (product.getProductCode().equals(detail.getProductCode())) {
Product p = product.addDetail(detail.category, detail.price);
productList.add(p);
}
});
});
return productList;
}
}
package de.scrum_master.stackoverflow.q77412076
import spock.lang.Specification
class ProductDetailTest extends Specification {
def 'test without mock'() {
expect:
new ProductDecorator().addProductFeature(products[0], productDetails) == [
new Product(name: 'One', productCode: 'XY-1', category: 'vegetables', price: 12.34),
new Product(name: 'Two', productCode: 'AB-2', category: 'flowers', price: 23.45),
new Product(name: 'Three', productCode: 'QR-3', category: 'vegetables', price: 34.56)
]
new ProductDecorator().addProductFeature(products[1], productDetails) == [
new Product(name: 'Four', productCode: 'XY-1', category: 'vegetables', price: 12.34),
new Product(name: 'Five', productCode: 'AB-2', category: 'flowers', price: 23.45),
new Product(name: 'Six', productCode: 'QR-3', category: 'vegetables', price: 34.56)
]
}
def 'test with mock'() {
given:
ProductDecorator productDecorator = Mock()
productDecorator.addProductFeature(products[0], productDetails) >> products[0]
expect:
productDecorator.addProductFeature(products[0], productDetails) == products[0]
productDecorator.addProductFeature(products[1], productDetails) == null
}
List<List<Product>> getProducts() {
[
[
new Product(name: 'One', productCode: 'XY-1'),
new Product(name: 'Two', productCode: 'AB-2'),
new Product(name: 'Three', productCode: 'QR-3')
],
[
new Product(name: 'Four', productCode: 'XY-1'),
new Product(name: 'Five', productCode: 'AB-2'),
new Product(name: 'Six', productCode: 'QR-3')
]
]
}
List<ProductDetail> getProductDetails() {
[
new ProductDetail(productCode: 'XY-1', category: 'vegetables', price: 12.34),
new ProductDetail(productCode: 'AB-2', category: 'flowers', price: 23.45),
new ProductDetail(productCode: 'QR-3', category: 'vegetables', price: 34.56)
]
}
}
Please note: The mock should return products[0]
rather than [products[0]]
, because ProductDecorator.addProductFeature
returns List<Product>
, not List<List<Product>>
. But that is not the root cause of your problem.
Try it in the Groovy Web Console.
There, I used the Groovy equivalent of your Lombok annotations for simplicity's sake. @Canonical
is like a combination of @ToString
, @EqualsAndHashCode
and @TupleConstructor
. While recreating your situation, I was also printing values, hence the wish to have nice toString()
methods. I also converted your lambdas into Groovy closures. Lambdas are fine in Groovy 4, but closures also work in older Groovy versions.