集合中的 Grails 实例修改

Grails instance modification in collection

我在两个类似的 Grails 3.3.5 测试用例中观察到不同的行为。两种情况的区别是:

我的问题是:根据 Java 和 Groovy 的面向对象范例,我希望这两个测试的行为都像第一个测试。为什么会有差异,具体取决于创建对象的 class?

为了清楚起见,我的代码示例如下。域名 class:

class MyTestObject {

    String value

    static constraints = {
    }

    MyTestObject(){
        value = "initialized"
    }

    void edit(){
        value = "edited"
    }

    String getValue(){
        value
    }
}

控制器class:

class MyTestController {

    def index() { }

    Map<Integer, MyTestObject> objects1
    Map<Integer, MyTestObject> objects2

    MyTestController(){
        objects1 = new HashMap<>()
        objects2 = new HashMap<>()
    }

    void addObject(){
        int count = objects1.size()
        objects1.put(count, new MyTestObject())
        objects2.put(count, new MyTestObject())
    }

    void addObject(MyTestObject testObject){
        int count = objects1.size()
        objects1.put(count, testObject)
        objects2.put(count, testObject)
    }

    MyTestObject getObjectFromCollection1(int atPosition){
        if (0 > atPosition || atPosition > objects1.size()-1){
            return
        }
        objects1.get(atPosition)
    }

    MyTestObject getObjectFromCollection2(int atPosition){
        if (0 > atPosition || atPosition > objects2.size()-1){
            return
        }
        objects2.get(atPosition)
    }

    void updateObjectInCollection1(int index, MyTestObject object){
        objects1.put(index, object)
    }

}

规格是:

import grails.testing.web.controllers.ControllerUnitTest
import spock.lang.Specification

class MyTestControllerSpec extends Specification implements ControllerUnitTest<MyTestController> {

    int index
    def setup(){
        index = 0
    }

    void "case 1: external object instantiation"() {
        MyTestController controllerLocal = new MyTestController()
        MyTestObject object = new MyTestObject()
        controllerLocal.addObject(object)
        object.edit()
        MyTestObject afterEditInCollection1 = controllerLocal.getObjectFromCollection1(index)
        MyTestObject afterEditInCollection2 = controllerLocal.getObjectFromCollection2(index)

        expect:
        "edited" == object.getValue()
        "edited" == afterEditInCollection1.getValue()
        "edited" == afterEditInCollection2.getValue()
    }

    void "case 2: internal object instantiation"() {
        MyTestController controllerLocal = new MyTestController()
        controllerLocal.addObject()
        MyTestObject toBeEditedLocally = controllerLocal.getObjectFromCollection1(index)
        toBeEditedLocally.edit()
        MyTestObject afterEditInCollection1 = controllerLocal.getObjectFromCollection1(index)
        MyTestObject afterEditInCollection2 = controllerLocal.getObjectFromCollection2(index)

        expect:
         "edited" == toBeEditedLocally.getValue()
         "edited" == afterEditInCollection1.getValue()
         "edited" == afterEditInCollection2.getValue()
    }

    def cleanup() {
    }

}

Why is there a difference, depending on which class is creating the object?

创建对象的 class 没有区别。该问题与创建实例的位置无关。问题是,在 addObject() 中,您正在创建 2 个单独的对象,将其中一个添加到 objects1,另一个添加到 objects2。在 addObject(MyTestObject) 中,您正在向 2 Map.

中的每一个添加相同的 MyTestObject 实例
void addObject(){
    int count = objects1.size()
    objects1.put(count, new MyTestObject())
    objects2.put(count, new MyTestObject())
}

void addObject(MyTestObject testObject){
    int count = objects1.size()
    objects1.put(count, testObject)
    objects2.put(count, testObject)
}

如果您将 addObject() 更改为如下所示,您的测试都会通过:

void addObject(){
    int count = objects1.size()
    def newTestObject = new MyTestObject()
    objects1.put(count, newTestObject)
    objects2.put(count, newTestObject)
}