是否有可用的框架或库,可以对JavaBean进行全面测试,包括测试所有getter和setter方法,验证属性是否与getter和setter方法匹配等?
是否有可用的框架或库,可以对JavaBean进行全面测试,包括测试所有getter和setter方法,验证属性是否与getter和setter方法匹配等?
虽然我同意有更大的问题需要解决,但对于测试Java bean方法的情况确实存在。在大型代码库上工作的大团队可能会遇到问题。我见过几种情况,复制/粘贴错误会导致getter或setter作用于错误的属性。健忘可能导致hashCode和equals方法不一致。在这段简单的代码中找到错误非常令人沮丧。
Bean Matchers是一个可以帮助解决问题的库。它提供了一系列Hamcrest匹配器,用于反射测试Java beans。例如:
@Test
public void testBean() {
assertThat(MyBean.class, allOf(
hasValidBeanConstructor(),
hasValidGettersAndSetters(),
hasValidBeanHashCode(),
hasValidBeanEquals(),
hasValidBeanToString()
));
}
很遗憾,2021年了这个问题仍然存在。
如果您的DevOps流水线对存储库施加覆盖率限制,那么Bean会增加代码库并产生非常负面的影响。有两种方法可以克服它。
排除bean(我认为不应该这样做)。
为bean编写测试用例(这是我们作为开发人员可以浪费时间的最可悲的事情 :( )。
在大多数情况下,您最终将为bean编写测试用例。
我编写了这个简单的实用程序/测试用例,它使用反射,并可以使您增加Junit代码覆盖率并节省时间。
测试的Bean:City
package com.test.beans;
import java.util.List;
/**
* @author ameena
*
*/
public class City {
private int postOffices;
private int jurdictaionAreas;
private double areaInSqMeter;
private long population;
private List<City> neighbourCities;
private boolean metro;
public int getJurdictaionAreas() {
return jurdictaionAreas;
}
public void setJurdictaionAreas(int jurdictaionAreas) {
this.jurdictaionAreas = jurdictaionAreas;
}
public double getAreaInSqMeter() {
return areaInSqMeter;
}
public void setAreaInSqMeter(double areaInSqMeter) {
this.areaInSqMeter = areaInSqMeter;
}
public long getPopulation() {
return population;
}
public void setPopulation(long population) {
this.population = population;
}
public int getPostOffices() {
return postOffices;
}
public void setPostOffices(int postOffices) {
this.postOffices = postOffices;
}
public List<City> getNeighbourCities() {
return neighbourCities;
}
public void setNeighbourCities(List<City> neighbourCities) {
this.neighbourCities = neighbourCities;
}
public boolean isMetro() {
return metro;
}
public void setMetro(boolean metro) {
this.metro = metro;
}
}
package com.test.beans;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
/**
* @author ameena
*
*/
class BeanTest {
public void invokeSetter(Object obj, String propertyName, Object variableValue)
{
PropertyDescriptor propDescriptor;
try {
propDescriptor = new PropertyDescriptor(propertyName, obj.getClass());
Method setter = propDescriptor.getWriteMethod();
try {
setter.invoke(obj,variableValue);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
fail(e.getMessage());
}
} catch (IntrospectionException e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public Object invokeGetter(Object obj, String variableName)
{
Object returnValue = null;
try {
PropertyDescriptor pd = new PropertyDescriptor(variableName, obj.getClass());
Method getter = pd.getReadMethod();
returnValue = getter.invoke(obj);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | IntrospectionException e) {
e.printStackTrace();
fail(e.getMessage());
}
return returnValue;
}
private <T extends Object> void validateGettersSetters(List<T> objects) {
for (T t : objects) {
Class<?> aClass = t.getClass();
for (java.lang.reflect.Field field : aClass.getDeclaredFields()) {
System.out.println(field);
Class<?> c = field.getType();
if (c == String.class) {
invokeSetter(t, field.getName(), "dummy");
assertEquals("dummy", (invokeGetter(t, field.getName())));
} else if (c == Integer.class || c == int.class) {
invokeSetter(t, field.getName(), 1);
assertEquals(1, (invokeGetter(t, field.getName())));
}else if (c == Double.class || c == double.class) {
invokeSetter(t, field.getName(), 1d);
assertEquals(1d, (invokeGetter(t, field.getName())));
}else if (c == Long.class || c == long.class) {
invokeSetter(t, field.getName(), 1l);
assertEquals(1l, (invokeGetter(t, field.getName())));
}else if (c == Boolean.class || c == boolean.class) {
invokeSetter(t, field.getName(), true);
assertEquals(true, (invokeGetter(t, field.getName())));
}else if (c == List.class){
//Now based on your bean and filed name
switch(field.getName()) {
case "neighbourCities" :
invokeSetter(t, field.getName(), new ArrayList<City>());
assertNotNull(invokeGetter(t, field.getName()));
break;
}
}
}
}
}
@Test
void testBean() {
List<Object> objects = new ArrayList<>();
objects.add(new City());
validateGettersSetters(objects);
}
}
没什么花哨的东西,但它为我节省了编写23个bean测试用例的时间 :)
问候 Amit Meena
如果你不想使用像http://commons.apache.org/validator/这样更高级的工具,我建议你自己编写。就个人而言,我不喜欢没有任何行为的纯数据持有对象,这不是很好的设计。因此,如果我不必(例如在使用j2ee时)使用这些对象,我会试着摆脱它们。
我猜这个库就是你问题的答案: http://outsidemybox.github.com/testUtils/
它测试所有bean的初始值、setter、getter、hashCode()、equals()和toString()。 你所要做的就是定义一个默认和非默认属性/值的映射。
它还可以测试具有额外非默认构造函数的bean对象。