2013-05-01 136 views
1

设置一些集成测试,我遇到了与域类相等的问题。在正常执行过程中,等于按预期工作,但在通过集成测试测试服务方法时,平等测试会返回错误。 (测试用例堪称设置())Grails集成测试 - 域对象相等

一个服务提出Domain对象到会话

SomeService { 
    setSessionVehicle(String name) { 
    Vehicle vehicle = Vehicle.findByName(name) 
    session.setAttribute("SessionVehicle", vehicle) 
    } 

    getSessionVehicle() { 
    return session.getAttribute("SessionVehicle") 
    } 
} 

其他地方的其他服务,我加载一个对象,并确保相关的属性对象相匹配的会话值:

OtherService { 
    getEngine(long id) { 
    Vehicle current = session.getAttribute("SessionVehicle") 

    Engine engine = Engine.get(id) 
    if(!engine.vehicle.equals(current)) throw Exception("Blah blah") 
    } 
} 

这工作正常运行期间如预期,从装错引擎防止(好吧,我消毒类名,假装这是有道理的)。但在集成测试,即.equals()失败时,它应该会成功:

Vehicle testVehicle 

setUp() { 
    Vehicle v = new Vehicle("Default") 
    v.save() 
    someService.setSessionVehicle("Default") 
    testVehicle = someService.getSessionVehicle() 
} 

testGetEngine() { 
    List<Engine> engines = Engine.findAllByVehicle(testVehicle) 
    //some assertions and checks 
    Engine e = otherService.getEngine(engines.get(0).id) 
} 

findAll()调用正确返回在会话中的车辆相关联的所有引擎的列表,但是当我尝试查找通过ID识别单个引擎,找到的引擎上的会话Vehicle vs Vehicle的相等性检查失败。此时只有一辆车已经创建,并且异常消息显示会话Vehicle和Engine.Vehicle存在并且具有相同的值。

如果我在testCase本身尝试这种相等性检查,它会失败,但我可以更改testCase来检查if(vehicle.id == sessionVehicle.id)哪个成功,但我并不热衷于更改我的生产代码以满足集成测试。

在我的测试用例中设置这些域对象时,我该做什么错误,我应该采取不同的方式?

回答

3

首先,你正在做的平等检查只是检查参考。你不应该使用你的检查的默认等号方法,更好的重写域类中的等号方法。

有两种方法可以覆盖equals方法:
1)您可以使用IDE为equals方法自动生成代码(大量的空检查等)。
2)首选方法:您可以使用Apache Commons项目中的EqualsBuilder和HashCodeBuilder类。该库应该已经可用于您的应用程序,或者下载JAR文件并放在lib中。
下面是使用EqualsBuilder示例代码:

  boolean equals(o) { 
       if (!(o instanceof Vehicle)) { 
        return false 
       } 
       def eb = new EqualsBuilder() 
       eb.append(id, o.id) 
       eb.append(name, o.name) 
       eb.append(otherProperties, o.otherProperties) 
      .... 
       return eb.isEquals() 
      } 

的另一点是:你如何在服务获取会话?来自RequestContextHolder?它不是直接从服务访问会话的好习惯,而是将值作为方法参数发送到服务中。

+0

谢谢你的回答,但这引发了其他问题,也许我一直在做错事。 1)我的印象是在grails域对象中忽略了'equals()'和'hashcode()',因为它独占地使用'id'属性,不管你如何在域中定义它。 2)是的,我从RequestContextHolder获取会话。我不确定将变量传递给每个方法是否可行,除非您意味着将其从控制器中的会话中取出,然后将其传递给服务?这是在每个**方法中使用的登录变量。 – Trebla 2013-05-02 10:34:45

+0

1)'equals()'和'hashcode()'不被忽略。如果比较equals方法中的所有属性,它将这样做,不仅是'id'属性。请在您的域名课程中覆盖这两者,进行一些测试并让我们知道结果。一个重要的注意事项:覆盖equals()时总是覆盖hashCode()。 HashSet和HashMap使用hashCode()首先调用equals()进行碰撞。 2)我打算在控制器中获取会话值,并将其传递给service方法作为参数。 – Shafiul 2013-05-02 14:47:16

+0

在我的日程安排允许之前需要一段时间,但添加equals和haschode可解决此问题。这是我对grails域对象的基本误解。 – Trebla 2013-05-14 18:17:03