WeakReference testen

Wat is de juiste aanpak om een ​​zwakke referentie in Java te testen?

Mijn eerste idee is om het volgende te doen:

public class WeakReferenceTest {

    public class Target{
        private String value;    

        public Target(String value){
            this.value = value;
        }    
        public String toString(){
            return value;
        }
    }

    public class UsesWeakReference{    
        WeakReference reference;   

        public UsesWeakReference(Target test){
            reference = new WeakReference(test);
        }    
        public String call(){
            Target test = reference.get();
            if(test != null){
                return test.toString();
            }
            return "empty";
        }
    }

    @Test
    public void testWeakReference(){    
        Target target = new Target("42");

        UsesWeakReference usesWeakReference = new UsesWeakReference(target);    
        WeakReference triggerReference = new WeakReference(target);    
        assertEquals("42", usesWeakReference.call());

        target = null;    
        while(triggerReference.get() != null){
            System.gc();
        }

        assertEquals("empty", usesWeakReference.call());    
    }    
}

De reservering die ik heb over de aanpak gebruikt System.gc (), omdat ik begrijp dat het anders kan gedragen op verschillende JVM's.

7

2 antwoord

Er is geen 100% bomvrije manier om code te testen die de referentietypes gebruikt. Het gedrag van Referentieobjecten is afhankelijk van wanneer de GC wordt uitgevoerd en er is geen 100% betrouwbare manier om de GC te dwingen om te worden uitgevoerd.

Het beste wat je kunt doen is:

  • controleer of u de juiste JVM-opties hebt ingesteld tijdens het uitvoeren van de tests en
  • schrijf uw test zodat deze niet faalt in het geval dat System.gc() een no-op OF is die bereid is de test uit te schakelen of over te slaan , of negeer de testfout.

(U zou moeten kunnen detecteren dat System.gc() genegeerd wordt door te kijken hoeveel geheugen er voor en na de oproep in gebruik is, bijv. Door Runtime.totalMemory() )


Eigenlijk is er een andere "oplossing". Laat de test van je unit een enorme hoeveelheid afval genereren ... genoeg om te garanderen dat je garbage collection activeert. (Geen goed idee, IMO.)

5
toegevoegd
Ik waardeer het antwoord ... valideert mijn standpunt.
toegevoegd de auteur John Ericksen, de bron

Nieuw antwoord op oude vraag; Ik heb je vraag gevonden, want ik heb te maken met exact hetzelfde probleem: ik wil een eenheidscontrole schrijven om te verifiëren dat mijn geteste klasse iets heel speciaals doet als de referent van een WeakReference null wordt.

Ik heb eerst een eenvoudige testcase geschreven die de referent op nul zou zetten; om vervolgens System.gc() aan te roepen; en interessant genoeg: tenminste in mijn eclips was dat "goed genoeg" om mijn weakRefernce.get() null te retourneren.

Maar wie weet of dat zal werken voor alle toekomstige omgevingen die deze unit-test voor de komende jaren zullen uitvoeren.

Dus na het nadenken over wat meer:

@Test
public void testDeregisterOnNullReferentWithMock() {
    @SuppressWarnings("unchecked")
    WeakReference weakReference = EasyMock.createStrictMock(WeakReference.class);
    EasyMock.expect(weakReference.get()).andReturn(null);
    EasyMock.replay(weakReference);
    assertThat(weakReference.get(), nullValue());
    EasyMock.verify(weakReference);
}

Werkt ook goed.

Betekenis: het generieke antwoord op dit probleem is een fabriek die WeakReference voor objecten voor u maakt. Dus als u uw productiecode wilt testen; je levert er een bespotte fabriek aan; en die fabriek zal op zijn beurt de WeakReference-objecten bespotten; en nu heb je de volledige controle over het gedrag van dat zwakke referentieobject.

En "volledige controle" is veel beter dan aannemen dat de GC misschien doet wat u hoopt dat het doet.

3
toegevoegd
Heel correct - ik heb nog een alinea toegevoegd om dat duidelijker te maken. Voor de goede orde: kan ik nog iets anders doen om deze opwachting waardig te maken in uw ogen?
toegevoegd de auteur GhostCat, de bron
Goed. U kunt een andere constructor gebruiken (die ik pakket beschermd zou maken); of bij het gebruik van Mockito is er de @InjectMocks-annotatie (die ik persoonlijk niet gebruik, omdat deze in stilte faalt - zodat je nooit weet of je moppen echt zijn geïnjecteerd).
toegevoegd de auteur GhostCat, de bron
Spotten is hier het beste, omdat GC niet perfect deterministisch of controleerbaar is.
toegevoegd de auteur kerner1000, de bron
Ik denk dat het al vrij duidelijk is. Ik moest een andere constructor maken voor mijn type dat ik wil testen om een ​​bespotte WeakReference te leveren (is een constructor die in de eerste plaats is voor het testen van schone code?;)). Misschien is het opmerkelijk dat het bespotten van de WeakReference het beste is voor reproduceerbare tests, maar minder 'realistisch', wat betekent dat als u expliciet onbetrouwbaar GC-gedrag wilt testen, dit misschien niet de beste aanpak is. (bedankt voor het upvote;))
toegevoegd de auteur kerner1000, de bron