WebHU - Programozási kérdések és válaszok

Hogyan kezeli Spock a megcsúfolt objektumok egyenlőségét?

A SortedSet of Library objektumokat használó osztály viselkedését tesztelem (a normál osztály nem interfész, ezért behoztam a cglib-nodep-et). Tesztelnem kell az osztály viselkedését, ha a rendezett halmaz több objektumot tartalmaz. A Library objektumokat a következő módon gúnyolták:

Library library = Mock()
Library library2 = Mock()

Ezután létrehozok egy TreeSetet:

def libraries = [library, library2] as TreeSet

és hívja meg a tesztelési módszer alatt lévő rendszert:

sut.doStuff(libraries).

A teszt hibakeresése során azt látom, hogy a könyvtárak csak egy elemből álló SortedSet. Úgy tűnik, hogy ez annak az eredménye, ahogy Spock kezeli az egyenlőséget:

def "equality test"() {
    expect:
        library == library2
}

átmegy, amikor lefuttatom a tesztet. Megkerülhetem valahogy ezt a viselkedést?

EDIT: == ==-ra változtattam, mert nem tudok gépelni


  • library = library2 sikeres, mert ez egy feladat, nem összehasonlítás? 28.08.2014
  • Igen, elnézést, csak gépelési hiba, valójában nem használtam a feladatot a tesztben 28.08.2014
  • Próbáltad inkább a library.is library2-t? Nem biztos benne, hogy mi az a Library, és hogyan valósul meg a equals() és a hashCode() vagy a compareTo(). 29.08.2014

Válaszok:


1

Kutatást végzett. Tekintse meg a következő tesztkészletet (groovy konzolszkript):

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
@Grab('cglib:cglib-nodep:3.1')

import spock.lang.*

class Test extends Specification {
    def "not comparable mocks are not equal"() {
        given:
        def a1 = Mock(A)
        def a2 = Mock(A)

        expect:
        a1.hashCode() != a2.hashCode()
        !a1.equals(a2)
        !(a1 == a2)        
    }

    def "comparable mocks are not equal"() {
        given:
        def a1 = Mock(AC)
        def a2 = Mock(AC)

        expect:
        a1.hashCode() != a2.hashCode()
        !a1.equals(a2)
        !(a1 == a2)        
    }

    def "cannot create TreeSet when POJOs are not comparable"() {
        given:
        def a1 = Mock(A)
        def a2 = Mock(A)

        and:    
        a1.hashCode() != a2.hashCode()
        !a1.equals(a2)
        !(a1 == a2)     

        when:
        new TreeSet([a1,a2])

        then:
        def e = thrown(ClassCastException)
        e.message.endsWith('cannot be cast to java.lang.Comparable')
    } 

    def "there's a problem with Comparable Mocks"() {
         given:
        def a1 = Mock(AC)
        def a2 = Mock(AC)

        and:    
        a1.hashCode() != a2.hashCode()
        !a1.equals(a2)
        !(a1 == a2)     

        when:
        def s = new TreeSet([a1,a2])

        then:
        s.size() == 2
    }

    def "with HashSet it works as expected"() {
        given:
        def a1 = Mock(AC) 
        def a2 = Mock(AC) 

        and:    
        a1.hashCode() != a2.hashCode()
        !a1.equals(a2)
        !(a1 == a2)     

        when:
        def s = new HashSet([a1,a2])

        then:
        s.size() == 2
    }
}

class A {}

class AC implements Comparable {

    int compareTo(Object o) {
        1 //whatever value may be here, it's not called
    }
}

Általában probléma van azzal, ha egy objektum megvalósítja a Comparable interfészt.

  1. Az első teszt azt mutatja, hogy ugyanazon objektumok különböző mockjei eltérő hash kódokkal rendelkeznek, és nem azonosak. Véleményem szerint ez az elvárt viselkedés.
  2. A második teszt ugyanazokat a feltételeket ellenőrzi, kivéve azt a tényt, hogy az objektumok Comparable. Nem sikerül. Véleményem szerint ez nem elvárt viselkedés.
  3. A harmadik teszt azt szemlélteti, hogy nem lehet TreeSet-et létrehozni nem összehasonlítható POJO-kkal. Elvárt viselkedés.
  4. A negyedik teszt az Ön által említett problémát szemlélteti. A két Comparable gúnnyal létrehozott TreeSet mérete várhatóan 2 lesz. Nem sikerül, a méret 1.
  5. Az ötödik teszt azt mutatja, hogy a 4-es teszt feltételei teljesülnek, ha HashSet-t használunk.

IMO ez nem a spock-hoz kapcsolódó probléma. Spock a cglib értéket használja a gúnyos objektumokhoz, és itt kell keresni a magyarázatot.

SZERKESZTÉS

Jól működik, ha a compareTo() metódus felül van írva álobjektumok esetén:

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
@Grab('cglib:cglib-nodep:3.1')

import spock.lang.*

class Test extends Specification {

    def "there's a problem with Comparable Mocks"() {
         given:
        def a1 = Mock(AC) {
            compareTo(_) >> 3145
        }
        def a2 = Mock(AC) {
            compareTo(_) >> 3146
        }

        and:    
        a1.hashCode() != a2.hashCode()
        !a1.equals(a2)
        !(a1 == a2)     

        when:
        def s = new TreeSet([a1,a2])

        then:
        s.size() == 2
    }
}

class AC implements Comparable {

    int compareTo(Object o) {
        1 //whatever value may be here, it's not called
    }
}
29.08.2014
  • Nem hiszem, hogy ez cglib probléma. A Cglib mindig delegálja a compareTo metódus meghívását. A delegálás megvalósítása bontja meg a kódot, és valószínűleg itt kell megoldást keresni. 29.08.2014
  • Nem ismerem elég jól a cglib és a spock megvalósítását. Ez csak egy kicsit köszönöm a visszajelzést. 29.08.2014
  • Talán a Spocknak ​​van egy tartaléka, ahol a Comparable gúnyokat egyenlővé teszi, ha összehasonlíthatók egymással. A gúnyolt metódusok alapértelmezés szerint a 0 értéket adják vissza, ha nincs másként megadva, így azt hiszem, a library.compareTo(library2) == 0 hívása. Ebben az összefüggésben az egyenlőségi teszt helyesen viselkedik. Vagy talán a Groovy objektumok viselkednek így? Nem igazán vagyok egy groovy srác. 29.08.2014
  • Megpróbáltam kigúnyolni a compareTo metódust, ami mindig visszatért 0 :/ 29.08.2014
  • Nem szabadna. Most próbáltam ki közvetlenül cglibben, és jól működik. 29.08.2014
  • Rendben, úgy tűnik, hogy probléma van a spockkal. Lehet, hogy később bejelentek egy problémát a GitHubon. 29.08.2014
  • A szerkesztés sikeres volt, köszönöm a segítségét. Az osztály eredetileg a Comparable-t valósította meg, így a probléma innen eredhetett. Köszönjük a megoldást a probléma bejelentése közben! 29.08.2014
  • Szívesen. Nem nyújtottam be semmilyen problémát a spock csapatnak, és nem vagyok biztos benne, hogy be kell-e nyújtani – ha úgy gondolja, nyugodtan folytassa. 29.08.2014
  • Valószínűleg felteszek egy problémát, és meglátjuk, mi a válasz. Ha hallok valamit, frissítem. 30.08.2014

  • 2

    Hacsak a equals() metódusa nem csonkolt, egy Mock() csak equals() maga. Azonban Groovy == nem mindig azt jelenti, hogy equals(). Comparables esetén c1.compareTo(c2) == 0-t jelent. Hasonlóképpen, a TreeSet a compareTo() értéket használja equals helyett az egyenlőség meghatározásához. Lehetséges megoldások:

    • Csökkentse a mock compareTo() metódusait, hogy megfelelő értékeket adjon vissza.
    • Ne használjon TreeSet-t.
    • Használjon valós objektumokat, amelyek a compareTo-t megfelelő módon valósítják meg, nem pedig gúnyokat.

    PS: Talán a Mock(Comparable) és/vagy a Stub(Comparable) automatikusan implementálja a compareTo-t a equals()-el összhangban álló módon. Tudsz ezzel kapcsolatos ügyet benyújtani?

    06.09.2014
    Új anyagok

    A rádiógomb ellenőrzött eseményének használata a jQueryben
    Ebben a cikkben látni fogjuk, hogyan kell dolgozni a jquery választógombbal ellenőrzött eseményeivel. A választógombok HTML gombok, amelyek segítenek kiválasztani egyetlen értéket egy csoportból...

    Körkörös függőségek megoldása terraformban adatforrásokkal – lépésről lépésre
    Mi az a körkörös függőségek Dolgozzunk egy egyszerű eseten, amikor az SQS-sor és az S3-vödör közötti körkörös függőség problémája van egy egymástól függő címkeérték miatt. provider..

    Miért érdemes elkezdeni a kódolást 2023-ban?
    01100011 01101111 01100100 01100101 — beep boop beep boop Világunk folyamatosan fejlődik a technológia körül, és naponta fejlesztenek új technológiákat a valós problémák megoldására. Amint..

    🎙 Random Noise #2  – Örökbefogadás és hit
    az analitika íratlan világának gondozása Szeretné, hogy ezek a frissítések a postaládájába kerüljenek? Iratkozzon fel itt . "Ha önvezető autókat gyártanak, akkor mi miért ne..

    A legrosszabb politika és prediktív modellek májátültetésre jelöltek számára az Egyesült Államokban
    A máj (vagy óangolul lifer) az emberi test legnehezebb belső szervére utal, amely csendesen működik a nap 24 órájában. Mit csinál a máj? 500 feladatot hajt végre a szervezet egészségének..

    5 webhely, amely 2022-ben fejleszti front-end fejlesztői készségeit
    Frontendmentor.io A tényleges projektek létrehozásával a Frontendmentor.io segítséget nyújt a front-end kódolási képességeinek fejlesztésében. A kódolást azután kezdheti meg, hogy..

    Mikor kell használni a Type-t az interfészhez képest a TypeScriptben?
    A TypeScript a JavaScript gépelt szuperkészlete, amely statikus gépelést ad a nyelvhez. Ez megkönnyíti a robusztus és karbantartható kód írását azáltal, hogy a hibákat a fordítási időben..