在实际场景中,我们比较两个对象是否相等,可能会去选择重写equals方法去比较对象里的每一个属性,或者是直接将对象的属性一个个取出来比较,但这都比较麻烦,Unitils为我们提供了反射断言可直接完成这一任务,如下例所示:
@Test
public void test1(){
User user1 = new User(1,"a","b");
User user2 = new User(1,"a","b");
System.out.println(user1 == user2);//false
ReflectionAssert.assertReflectionEquals(user1, user2);//断言成功
}
断言方法的完整方法签名为:assertReflectionEquals(Object expected, Object actual, ReflectionComparatorMode... modes
第一个参数为期望值,第二个为实际值,第三个为断言模式,有一下三种:
断言模式 | 说明 |
---|---|
ReflectionComparatorMode.LENIENT_ORDER | 忽略断言集合或数组中元素的顺序,如list(1,2,3)和list(3,2,1)将视为相等(括号内为集合的值) |
ReflectionComparatorMode.IGNORE_DEFAULTS | 忽略Java类型默认值,如引用类型为null,整数类型为0,布尔类型为false等如我们只想比较两个用户的id和名称是否相同,而忽略密码比较User("id","name","password") ,User("id","name",null) 则这两个对象是相等的 |
ReflectionComparatorMode.LENIENT_DATES | 比较两个日期只比较是否都是值,或者都是null的而忽略具体的日期数值 |
unitils还未我们提供了既忽略顺序、又忽略默认值的断言方法:
.assertLenientEquals(Object expected, Object actual)
使用方法类似与对象断言,下面是两个实例:
assertPropertyLenEquals("id", 1, user); //断言user的id属性的值是1
assertPropertyLenEquals("address.street", "First street", user); //断言user的address的street属性
反射属性断言有多种重载方式,下面是两种集合重载,他会比较:集合actualObjects中的所有对象的成员属性propertyName是否和集合actualObjects匹配,这里存在同样存在顺序的问题、默认值、日期数值的断言模式区分。
1. assertPropertyReflectionEquals(String propertyName, Collection<?> expectedPropertyValues, Collection<?> actualObjects, ReflectionComparatorMode... modes)
2. assertPropertyLenientEquals(String propertyName, Collection<?> expectedPropertyValues, Collection<?> actualObjects)
下面是一个实例:
User user1 = new User(2,"a","b");
User user2 = new User(3,"a","b");
ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(null, 2), Arrays.asList(user1,user2));//true
//junit.framework.AssertionFailedError: Expected: [3], actual: [2, 3]
ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(3), Arrays.asList(user1,user2));
ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(3,2), Arrays.asList(user1,user2));//true
//junit.framework.AssertionFailedError: Expected: [3, 4], actual: [2, 3]
ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(3,4), Arrays.asList(user1,user2));
使用unitils测试能简化我们的测试配置,下面看一个web测试实例:
public class UnitilsTestSpring extends UnitilsJUnit4{
@SpringApplicationContext("servlet-context.xml")//初始化spring容器
private ApplicationContext applicationContext;
@SpringBeanByType//根据类型注入控制器
private UserController userController;
@Test
public void test1(){
User user = new User(10,"name","password");
userController.getUser(user);
//输出User [id=10, userName=name, password=password]
}
}
其中注入属性有三种方法,
1. @SpringBeanByType:从Spring容器中加载一个与被注解属性相同类型的Bean,找不到则抛出异常
2. @SpringBeanByName:从Spring容器中加载一个与被注解属性相同名称的Bean
3. @SpringBean(value = “myId”):从Spring容器中加载一个id为myId的Bean
在这里我们针对web层测试而专门提到了RestTemplate和Unitils,它们不仅能完成单元测试,在集成测试方面也十分便利。后面在引入service层和dao层配置后,我们还会引入其他单元测试利器,如mock模拟测试以及DBunit数据库测试等。通过合理的单元测试和集成测试有助于我们实际项目的高效开发。