测试的时候常常要比较实际获得的对象是否相同于期望的对象,这类对象一般是JavaBean。

比较容易想到的方法是用JavaBean的各个getters获得相应的成员属性值,逐一比较:assertEquals(obj1.getXXX(),obj2.getXXX());

这种方法无疑是最繁琐的。

再则使用反射机制:

for(String prop:props){ // props为JavaBean的成员方法名字数组

Method method = obj1.getClass().getDeclaredMethod(prop);

assertEquals(method.invoke(obj1),method.invoke(obj2));

}

这种情况的比较常常用于JavaBean,可以利用getter命名规则,直接构造成员属性数组:

for(String prop:props){ // props为JavaBean的成员属性名字数组

Method method = obj1.getClass().getDeclaredMethod("get"

+prop.substring(0,1).toUpperCase()+prop.substring(1));

assertEquals(method.invoke(obj1),method.invoke(obj2));

}

Unitils里使用ongl框架实现JavaBean成员属性的比较:

ReflectionAssert. assertPropertyLenientEquals(java.lang.String propertyName,

java.lang.Object expectedPropertyValue, java.lang.Object actualObject);

这种方法依赖构造的成员方法或成员属性的名字,且是硬编码,不容易重构,即使是使用属性文件,将硬编码抽出,属性文件要维护起来也比较麻烦。有多少个成员属性就需要写多少条assertPropertyLenientEquals(...)。再则参照上面的方法,将propertyName构造成数组,然后遍历比较。

事实上可以不用反射机制而又能避免第一种繁琐比较的方法:简单的利用equals()方法重写!

Java里面的相等,至少有两种情况:(两个对象obj1和obj2)

l 第一种相等(==):两个句柄(或叫引用)指向了同一个对象;即obj1==obj2为true

l 第二种相等(equal):两个对象里包含的成员属性对应相等;

Object类中equals()方法定义:

public boolean equals(Object obj) {

return (this == obj);

}

一般自定义的类,为使equals()方法名副其实,都需要对它进行重写。

在举例子先介绍下例子中几个JavaBean的关系:

其中User、POJO、Item重写了equals()方法。

POJO中重写equals()可以方便的利用eclipse工具自动生成代码的功能:

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if(getClass() != obj.getClass())

return false;

final POJO other = (POJO) obj;

if (id == null) {

if (other.id != null)

return false;

} else if(!id.equals(other.id))

return false;

if (owner == null) {

if(other.owner != null)

return false;

} else if (!owner.equals(other.owner))

return false;

if (pic == null) {

if (other.pic != null)

return false;

} else if(!pic.equals(other.pic))

return false;

if (title == null) {

if (other.title != null)

return false;

} else if (!title.equals(other.title))

return false;

if (url == null) {

if (other.url != null)

return false;

} else if (!url.equals(other.url))

return false;

return true;

}

当然POJO中的owner为User对象,User对象的equals()方法也要重写。

Item继承自POJO,其equals()重写可以如下:

@Override

public boolean equals(Object obj) {

if(!super.equals(obj))

return false;

if(!(obj instanceof Item))

return false;

Item that = (Item)obj;

if(this.currPrice == null && that.currPrice == null)

// 注意这里一定是this.XX.equals(that.XX)[因为使用了短路与&&],以免出现

// NullPointerException

if(this.remainTime == null && that.remainTime == null

||this.remainTime.equals(that.remainTime))

return true;

if(this.remainTime == null && that.remainTime == null

&& this.currPrice.equals(that.currPrice))

return true;

if(this.currPrice.equals(that.currPrice)

&& this.remainTime.equals(that.remainTime))

return true;

return false;

}

当然也可以方便的使用代码自动生成:

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (!super.equals(obj))

return false;

if (getClass() != obj.getClass())

return false;

final Item other = (Item) obj;

if (currPrice == null) {

if (other.currPrice != null)

return false;

} else if (!currPrice.equals(other.currPrice))

return false;

if (remainTime == null) {

if (other.remainTime != null)

return false;

} else if (!remainTime.equals(other.remainTime))

return false;

return true;

}

于是:

@Test

public void testItemEqual() {

Item item1 = new Item(2l,new User(1l,"pwd","name"),"title","pic","url",

15.0f,new Date());

Item item2 = new Item(2l,new User(1l,"pwd","name"),"title","pic","url",

15.0f,new Date());

// 一句assertEquals搞定

assertEquals(item1, item2);

}

这样看来似乎价值还不是很大,再来看ItemList比较,顺便介绍下Comparator接口:

public void testItemListEqualV2() {

List itemList1 = new ArrayList();

List itemList2 = new ArrayList();

for(int i=0;i<10;i++)

itemList1.add(new Item((long)i,new User((long)i,"pwd","name"),

"title","pic","url",15.0f,new Date()));

for(int i=9;i>=0;i--)

itemList2.add(new Item((long)i,new User((long)i,"pwd","name"),

"title","pic","url",15.0f,new Date()));

int size = itemList1.size();

// 以上准备数据,可以略过

// 开始比较

assertEquals(size, itemList2.size());

Item[] itemArray1 = new Item[size];

Item[] itemArray2 = new Item[size];

Arrays.sort((Item[])itemList1.toArray(itemArray1), new ItemComparator());

Arrays.sort((Item[])itemList2.toArray(itemArray2), new ItemComparator());

for(int j =0 ; j

assertEquals(itemArray1[j],itemArray2[j]);

}

}

class ItemComparator implements Comparator{

public int compare(Item item1, Item item2) {

if(item1.getId() < item2.getId())

return -1;

else if(item1.getId() > item2.getId())

return 1;

else

return 0;

}

}

思路就是将期望list和实际list进行排序后逐个比较,这里明显有一个好处,可以明确的知道list中哪个位置的对象assertEquals() 失败。

到此结束了吗?看也没有什么多大好处,重写equals()照样费事?

当然不是!第三种相等!想怎么比较就怎么比较!!

往往开发并不会给我们重写好equals(),当然测试也不能随便改开发的代码。

看我怎么比较没有重写equals()的Blog对象,又是代码:

@Test

public void testBlogEqual() {

Blog blog1 = new Blog(4l,new User(1l,"pwd","name"),

"title","pic","url","description"){

@Override

public boolean equals(Object obj){

if(super.equals(obj)){

if(obj instanceof Blog){

Blog that = (Blog)obj;

if(this.getDescription() == null

&& that.getDescription() == null)

return true;

if(this.getDescription().equals(that.getDescription()))

return true;

}

}

return false;

}

};

Blog blog2 = new MockBlog(4l,new User(1l,"pwd","name"),

"title","pic","url","description");

Blog blog3 = new Blog(4l,new User(1l,"pwd","name"),

"title","pic","url","description");

Blog blog4 = new Blog(4l,new User(1l,"pwd","name"),

"title","pic","url","description4");

assertEquals(blog1, blog3);  // success

assertEquals(blog2, blog3);  // success

assertEquals(blog1, blog4);  // fail

assertEquals(blog2, blog4);  // fail

assertEquals(blog4, blog1);  // success,原因是Blog的超类POJO重写了equals()

assertEquals(blog4, blog2);  // success

}

class MockBlog extends Blog{

public MockBlog() {

super();

}

public MockBlog(Long id, User user, String title, String pic,

String url, String description) {

super(id, user, title, pic, url, description);

}

public MockBlog(Long id, User user) {

super(id, user);

}

@Override

public boolean equals(Object obj){

if(super.equals(obj)){

// 注意这里一定是查看是否Blog的实例

if(obj instanceof Blog){

Blog that = (Blog)obj;

if(this.getDescription() == null

&& that.getDescription() == null)

return true;

if(this.getDescription().equals(that.getDescription()))

return true;

}

}

return false;

}

}

说明一下:测试方法testBlogEqual()中blog1、blog2、blog3里面各个成员的值都相等(equal)、blog4的description不同。blog1和blog2都是Blog子类的实例,只不过blog1是Blog匿名子类的实例。可以看到几个assertEquals()的结果如注释。其中需要说明的是:

看Assert.assertEquals()源码

static public void assertEquals(String message, Object expected, Object actual) {

if (expected == null && actual == null)

return;

if (expected != null && expected.equals(actual))

return;

failNotEquals(message, expected, actual);

}

这里可以看出assertEquals()实际调用的是expected对象的equals方法,所以只管对期望对象进行mock!

于是再举个例子:Shop(id,owner,title,pic,url,buyNo),只想要比较id和buyNo

@Test

public void testShopEqual() {

Shop shop1 = new Shop(1l,new User(1l,"pwd","name"),"title","pic1","url1",20l){

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj instanceof POJO) {

POJO other = (POJO) obj;

if (id == null) {

if (other.getId() != null)

return false;

} else if (!id.equals(other.getId()))

return false;

}

if (!(obj instanceof Shop))

return false;

final Shop other = (Shop) obj;

if (this.getBuyerNo() == null) {

if (other.getBuyerNo() != null)

return false;

} else if (!this.getBuyerNo().equals(other.getBuyerNo()))

return false;

return true;

}

};

Shop shop2 = new Shop(1l,new User(1l,"pwd","name"),"title","pic2","url2",20l);

assertEquals(shop1, shop2);

}

assertEquals()通过。

以上因为Shop又继承POJO,所以equals()重写得有些复杂,一般JavaBean都直接继承Object,就没有这么复杂了。

为了重用新写的equals()方法,可以将你名字类mock为一个内部类(外部类当然也可以)。

再举一例:常常在进行数据库校验之前需要assertNotNull(),以User为例

@Test

public void testUserNotNull() {

User user1 = new User(){

@Override

public boolean equals(Object obj) {

if((obj instanceof User)){

User that = (User)obj;

if(that.getId()!=null && that.getName()!=null && that.getPassword()!=null)

return true;

}

return false;

}

};

User user2 = new User(1l,"pwd","name");

assertEquals(user1, user2);

}

再结合Debug工具,也很快就能定位到哪个属性值为null。

That all , enjoy!

java obj1 = obj2_无障碍assertEquals(Object obj1,Object obj2),想怎么比较就怎么比较!! [ 光影人像 东海陈光剑 的博客 ]...相关推荐

  1. java用正则表达式判断字符串中是否仅包含英文字母、数字和汉字_灵思致远Leansmall的博客-CSDN博客_java判断字符串只包含数字字母

    import java.util.regex.Matcher; import java.util.regex.Pattern;public class StrValidate {// 纯数字priva ...

  2. Java面向对象思想OOP理解 东海陈光剑 剑魔书仙读书录

    /****/ package iSword;import java.util.Scanner;/*** @author root**///*****************************主类 ...

  3. java支持html5视频流技术Pseudostreaming – Roden的专栏 – CSDN博客

    文章目录[隐藏] java支持html5视频流技术Pseudostreaming 首页博客学院 下载论坛APP 问答商城活动VIP会员专题招聘ITeyeGitChat 图文课 写博客 消息 登录注册 ...

  4. java object.getclass_Java Object getClass() 方法

    Object getClass() 方法用于获取对象的运行时对象的类. 语法 object.getClass() 参数 无.> 返回值 返回对象的类. 实例 以下实例演示了getClass()方 ...

  5. 从 Java 到 Scala(二):object

    本文由 Rhyme 发表在 ScalaCool 团队博客. object是一种让静态回归常态.打破模式.天然的语言特性. 其实在写这篇文章之前,我思绪万千,迟迟不能落笔,总想着自己会不会遗漏了某个知识 ...

  6. java之Thread.sleep(long)与object.wait()/object.wait(long)的区别及相关概念梳理(good)

    一.Thread.sleep(long)与object.wait()/object.wait(long)的区别 sleep(long)与wait()/wait(long)行为上有些类似,主要区别如下: ...

  7. JAVA学习笔记--类型转换(父类子类 Object 基本类型 String) 拆装箱 包装类

    最近一段时间忙着学习JAVA,本来net学的也不怎么好,趁着这个机会转下方向学习JAVA.不过.NET core的开源还是有点搞头的,微软了解一下.接下来几天我也会陆续写一些内容关于线程和集合等方面, ...

  8. 第三次学JAVA再学不好就吃翔(part45)--Object类

    学习笔记,仅供参考 文章目录 API概述 Object类 hashCode()方法 getClass()方法 toString()方法 equals()方法 ==与equals()方法的区别 API概 ...

  9. java的class和object_Java中Class/Object/T的关系

    Object 对象 Object是Java中的基类,大部分的对象都是继承于这个类. public class Object { .... public native int hashCode(); p ...

最新文章

  1. C# 目录必须是上个文本框的子级目录
  2. Solr学习之一 --------环境搭建
  3. python turtle库setpos_Python内置海龟(turtle)库绘图命令详解(二)
  4. oracle 查询时间点数据_ORACLE中查询时间点前后一分钟的数据
  5. 麦迪逊大学计算机科学咋样,威斯康星大学麦迪逊分校
  6. 给技术型创业者的几点建议
  7. jquery操作html小技巧
  8. Python+Selenium+Edge浏览器安装与简单运行(1/2)
  9. (4)Redis的Java API
  10. 一个屌丝程序猿的人生(三十九)
  11. MySQL的连接字符串 concat、concat_ws、group_concat、repeat()函数用法
  12. 女版乔布斯的覆灭,这是今年我听过最唏嘘的真人故事
  13. 掘金万亿级市场,F5G开启湖北全光智慧城市
  14. 解决:(iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8082 -j DNAT --to-destin
  15. E3来了,今年有哪些令人期待的游戏新作?
  16. 使用 Scrapy 框架对重复的 url 无法获取数据,dont_filter=True
  17. 第一章 数据仓库理论专题
  18. keras 使用WGAN-div进行图像生成
  19. 十一课堂|通过小游戏学习Ethereum DApps编程(1)
  20. The second day :天猫精灵玩法之创建意图,实现对话功能

热门文章

  1. 视频内容理解核心技术解密:Partial re-ID 在成片体检中的技术实践
  2. 软件机器人从幕后到台前 RPA+Chatbot带来“端到端的自动化”
  3. 34000+技术博主齐聚,一周发文近 20,000 篇,网友:啥活动?
  4. 图灵奖背后:一个奥斯卡拿到手软,一个公司卖了 160 亿
  5. 稳定=死亡!废掉一个人的最好办法,就是让他瞎努力......
  6. 300 秒带你吃透大数据!
  7. 直接拿来用!Visual Studio 扩展工具利用 AI 强化你的代码
  8. 高通 AI、5G 争夺战!
  9. Windows 10 终于干掉了 Windows 7!
  10. 如何转移 Github 的 Star?