[java] junit dood?

Pagina: 1
Acties:

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
De afgelopen tijd is het mij opgevallen dat ik nog maar weinig berichten hoor over extreme programming (agile programming wel trouwens) en tevens niet veel meer over het unit testen en dan vooral JUnit. De versie daar online staat is al erg oud en is al in geen tijden meer geupdate. Ik vind dit vrij jammer want er valt nog meer dan genoeg erin te verbeteren. Testen van subclasses is erg lastig (dit reken ik ze heel zwaar aan) en verder zitten er genoeg gaten in het framework (oa parameters meegeven aan testcases en mbv reflectie de juiste testmethodes aanroepen). Ik zit er over te denken om nu maar eens naar een ander testframework over te stappen, want deze tool begint intussen aardig onwerkbaar te worden.

Dit valt namelijk onder mijn categorie:
wat niet meer geupdate wordt, dat bestaat niet.

[ Voor 9% gewijzigd door Alarmnummer op 16-05-2005 09:32 ]


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Hum, JUnit mag al een tijdje meer niet zijn geupdate, het is nog steeds hét standaard framework voor het schrijven van (Unit) Tests, en heeft de beste integratie met andere tools zoals IDE's, build tools en rapportage/coverage. JUnit is een relatief simpel framework, en de basis is "af", dus waarom nog updates? Ik ben het absoluut niet eens met de stelling: wat niet geupdate wordt, dat bestaat niet. Een framework is dood als het niet meer gebruikt/ondersteund wordt. JUnit is nog verreweg de meest bekende test tool voor Java en echt niet dood.

Voor de mensen die wat geavanceerders willen is er TestNG. Dat maakt gebruik van annotations en wat geavanceerdere trucs om wat minder boilerplate code voor de tests hoeven te schrijven. Het is fundamenteel echter niet zo veel anders dan JUnit, en met tools als junitx kun je hetzelfde effect ook bereiken, zonder dat je Java 5 annotations nodig hebt (de meeste projecten werken nog niet met Java 5).

Met JUnit kun je prima subklasses testen, alleen niet geïsoleerd van de superklasse. Om subclasses geïsoleerd te kunnen testen moet je (runtime) bytecode modificaties uitvoeren, eventueel via een AOP constructie oid. JUnit is een basisframework waar dit soort spannende dingen niet in zit. Het zou kunnen met tools als virtualmock of met mijn tooltje mockassist, die beide integreren met JUnit (beide tools zijn overigens door hun makers inmiddels als noodzakelijk kwaad bestempeld).

De meeste mensen zijn (terecht) huiverig van tools die een bytecode modificatie op de testsituatie uitvoeren waarbij het gedrag van de code wordt beïnvloed. Als je subklasses echt in isolatie wilt testen is dit misschien een teken dat het gedrag van de superklasse eigenlijk geen onderdeel is van de subklasse. Dan kun je beter compositie ipv inheritance gebruiken, wat makkelijker te isoleren is en een duidelijkere scheiding in gedrag geeft.

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Oh ja, en van Extreme Programming is afgelopen november nog een nieuwe "versie" verschenen: Extreme Programming Explained : Embrace Change (2nd Edition). Ook nog niet dood dus. ;)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
misfire schreef op maandag 16 mei 2005 @ 12:40:
Hum, JUnit mag al een tijdje meer niet zijn geupdate, het is nog steeds hét standaard framework voor het schrijven van (Unit) Tests, en heeft de beste integratie met andere tools zoals IDE's, build tools en rapportage/coverage.
Mwuah.. veel coverage tools werken mbv bytecode enhancements en werken net zo goed met junit als een ander testframework. Zo lang de code maar gedraait wordt doet de coverage meter het.
Met JUnit kun je prima subklasses testen, alleen niet geïsoleerd van de superklasse.
:?

Ik wil jou wel eens een testsuite zien maken subclasses waar je de instantie niet mag meegeven via de constructor want je wilt alle testxxx methodes uitvoeren en niet laten aankomen op een runtest. Het is een algemeen bekend fout dat junit je daar in de steek laat.
Om subclasses geïsoleerd te kunnen testen moet je (runtime) bytecode modificaties uitvoeren, eventueel via een AOP constructie oid.
Komen we aan bij mijn andere kreet:
wat niet makkelijk is, bestaat niet.

Als ik in de praktijk te veel zaken moet doen om een simpele test te verrichten, dan doe ik het niet. Simpel as that. En alles wat ik niet doe, kan net zo goed niet bestaan.

Met dit soort ondersteunde zaken ben ik erg pragmatisch.
De meeste mensen zijn (terecht) huiverig van tools die een bytecode modificatie op de testsituatie uitvoeren waarbij het gedrag van de code wordt beïnvloed. Als je subklasses echt in isolatie wilt testen is dit misschien een teken dat het gedrag van de superklasse eigenlijk geen onderdeel is van de subklasse. Dan kun je beter compositie ipv inheritance gebruiken, wat makkelijker te isoleren is en een duidelijkere scheiding in gedrag geeft.
Tja.. en wat dacht je van interfaces opstellen inclusief unit tests daarvoor. Zodat je alle implementaties van die interface met dezelfde unit test kan testen, ipv dat je voor iedere implementatie opnieuwe een testcase moet maken.

Volgens mij test jij je subclasses ook niet want je komt niet met praktische oplossingen aan.

[ Voor 8% gewijzigd door Alarmnummer op 16-05-2005 14:15 ]


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Alarmnummer schreef op maandag 16 mei 2005 @ 13:34:
[...]

Mwuah.. veel coverage tools werken mbv bytecode enhancements en werken net zo goed met junit als een ander testframework. Zo lang de code maar gedraait wordt doet de coverage meter het.
Sommige coverage tools kunnen aangeven welke test welke code raakt, daar is wel degelijk een bepaalde JUnit integratie voor nodig.
[...]

:?

Ik wil jou wel eens een testsuite zien maken subclasses waar je de instantie niet mag meegeven via de constructor want je wilt alle testxxx methodes uitvoeren en niet laten aankomen op een runtest. Het is een algemeen bekend fout dat junit je daar in de steek laat.
JUnit voert inderdaad met runtest allee testxxx methodes één voor één uit, of maar één specifieke testxxx als je dit aangeeft. Wat je bedoelt met de instantie via de constructor snap ik niet.
[...]

Komen we aan bij mijn andere kreet:
wat niet makkelijk is, bestaat niet.

Als ik in de praktijk te veel zaken moet doen om een simpele test te verrichten, dan doe ik het niet. Simpel as that. En alles wat ik niet doe, kan net zo goed niet bestaan.
Op zich vind ik het wel interessant waarom dat frameworks als virtualmock bestaan, en welke conclusie die makers zelf verbinden aan het gebruik hiervan. Je weet pas dat een oplossing niet simpel is op het moment dat je inzicht hebt in de inspanning en complexiteit die er voor nodig is. Ipv zelf het wiel uit te vinden is het makkelijker om op basis van bestaande frameworks te concluderen dat AOP/bytecode modificatie in unit tests waarschijnlijk overkill is. Wat niet makkelijk is, bestaat voor mij wel, zodat ik daarvan leer dat ik het niet moet doen, en waarom niet.
[...]

Sorry.. totaal onzin. *moppelt iets over interfaces en instanties van die interfaces en tests op stellen voor interfaces*.

Volgens mij test jij je subclasses ook niet want je komt niet met praktische oplossingen aan.
Als je schrijft dat iets onzin is, schrijf er dan ook bij waarom, dan kan ik er verder op ingaan. Subklasses geïsoleerd testen van de superklasse kan met bytecode modificatie of redesign naar een compositie. Dat zijn de enige twee manieren om het te doen, onafhankelijk van het framework wat je verder gebruikt.

Het ándere probleem wat je noemt: tests op stellen voor interfaces, is in principe een iets subtieler probleem. Unit Tests zijn namelijk white-box tests, dus je test met kennis van code in je test. Aangezien in interfaces geen code zit ga je deze niet testen, maar schrijf je aparte testcases voor je verschillende implementaties van die interface. Een beetje flauw antwoord natuurlijk, en om je niet helemaal woest te maken geef ik je toch een oplossing hoe je dit in JUnit kunt doen: ;)

Interface:
code:
1
2
3
4
5
6
7
package foo;

public interface Foo {
    
    public void bar(String bla);

}

Testcase:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package foo;

import junit.framework.TestCase;

public class FooTest extends TestCase {

    public static interface FooFactory {
        public Foo createFoo();
    }

    private Foo foo;

    private FooFactory fooFactory;

    public void setFooFactory(FooFactory fooFactory) {
        this.fooFactory = fooFactory;
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        foo = fooFactory.createFoo();
    }

    public void testBar() {
        foo.bar("bla");
    }
}

Testsuite:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package foo;

import java.util.Enumeration;

import junit.framework.Test;
import junit.framework.TestSuite;

public class FooTests {

    public static Test suite() {
        TestSuite suite = new TestSuite("Tests for Foo interface");
        suite.addTest(createFooTestSuite(new FooTest.FooFactory() {
            public Foo createFoo() {
                return new FooImpl("bla bla", 2);
            }
        }));
        suite.addTest(createFooTestSuite(new FooTest.FooFactory() {
            public Foo createFoo() {
                return new FooImpl2("foo foo", 2.4d);
            }
        }));
        return suite;
    }

    private static Test createFooTestSuite(FooTest.FooFactory fooFactory) {
        TestSuite fooImplTestSuite = new TestSuite(FooTest.class);
        Enumeration fooImplTestEnum = fooImplTestSuite.tests();
        while (fooImplTestEnum.hasMoreElements()) {
            ((FooTest) fooImplTestEnum.nextElement()).setFooFactory(fooFactory);
        }
        return fooImplTestSuite;
    }
    
}
Als je dit allemaal wat vriendelijker wilt maken kun je ook zelf een subklasse maken van TestCase of TestSuite, en/of het combineren met generics en andere fancy dingetjes. Wie weet, als je op internet zoekt, vind je al zoiets van anderen. Dan hoef je geen nieuw framework te leren, tools te zoeken, build routines aan te passen enz. Een kreet van mij: if it isn't broke, don't fix it.

[ Voor 5% gewijzigd door misfire op 16-05-2005 14:49 ]


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Mag ik uit het uitblijven van een reactie opmaken dat JUnit zo slecht nog niet is? ;)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
misfire schreef op vrijdag 20 mei 2005 @ 20:06:
Mag ik uit het uitblijven van een reactie opmaken dat JUnit zo slecht nog niet is? ;)
Ik heb niet gezegd dat JUnit slecht was (ik gebruik het al jaren). Ik heb gezegd dat Junit niet echt meer in ontwikkeling is en dat er een aantal gaten zijn die nog steeds niet zijn opgevuld. Aangezien ik niet swerelds zwaarste en beste tester ben, vind ik het maar vreemd dat hier gewoon geen oplossing voor is.

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Van mij mogen sommige dingen in JUnit ook wel beter en makkelijker. Ik merk echter in mijn praktijksituatie dat de meeste "gaten" in JUnit stiekem best aardig kunnen, als je maar een beetje creatief met het framework bent. Er zijn van JUnit zelf geen nieuwe versies, maar er is nog genoeg ontwikkeling op het gebied van tooling en aanvullende frameworks voor JUnit, dus stil (of dood) zou ik niet zeggen.

Frameworks als TestNG bieden aardige nieuwe dingen, zoals het groeperen op methode niveau zodat je zelf onderscheid kunt maken tussen slow running en fast running tests, en directe ondersteuning voor parameters.

Die aanpassingen komen echter wel met een prijs. Geen support voor JDK 1.3 (is nog steeds mijn uitgangspunt), brakke support voor JDK 1.4 (XDoclets zijn niet ideaal voor dit soort toepassingen). De support voor parameters in TestNG vind ik bijvoorbeeld aan de ene kant mooi (dependency injection), aan de andere kant maakt dit je testcases afhankelijk van een externe bron. Dit maakt het moeilijker om tests te hergebruiken of ad-hoc aan te roepen. De keuze om methodenamen en klassenamen als string onder te brengen in parameters/config files zorgt ervoor dat automatisch refactoren of afhankelijkheids-analyses in de IDE niet meer kan. Test dependencies op kunnen geven klinkt leuk, maar het kan mij eigenlijk niet zo veel schelen hoe veel testen er mis gaan, binnen een geïsoleerde test zou ik de fout zowieso makkelijk moeten kunnen vinden. Nu moet ik ineens gaan nadenken over test afhankelijkheden, wat als ik daar fouten in maak, en testen worden onterecht geskipped?

Als je alles bij elkaar optelt dan zie ik TestNG op dit moment als enige alternatief voor JUnit, en alleen de moeite waard als je JDK 1.5 en Eclipse 3.1 gebruikt. Dan nog krijg je voor een paar extra verbeteringen een complexer executiemodel en minder mogelijkheden binnen de IDE om dingen te bekijken of aan te passen.

De punten die jij aanhaalt (subklasses/interfaces testen) of zaken als inner klasses testen worden niet specifiek geadresseerd in TestNG, dus je zult daar zelf creatieve dingen voor moeten blijven doen. Ik denk ook dat het niet zo erg is dat je af en toe zelf wat moet nadenken om dit soort alternatieve testen te implementeren. In .NET is de meest vooruitstrevende Unit Test implementatie MbUnit. Er staat hier een voorbeeld van de geavanceerde interface test mogelijkheden in MbUnit. Als ik dit zie dan denk ik: leuk voorbeeld, maar is dit niet een kanon op een mug? Is dit niet tegenstrijdig met het white-box testmodel van Unit Testen? Ook voor unit test frameworks geldt de KISS regel, en daar voldoet JUnit prima aan. :)

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
In dit interview staat het volgende citaat:
Actually, the JUnit journey isn't over yet and Kent and I are currently working on JUnit 4. We are continuing to evolve JUnit in a test-driven way. One of our themes is to lower the barriers to entry. To do so we are leveraging J2SE 5 features like annotations to make JUnit easier to use.
Ze zijn er dus weer mee bezig. :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
misfire schreef op zaterdag 21 mei 2005 @ 13:12:
Van mij mogen sommige dingen in JUnit ook wel beter en makkelijker. Ik merk echter in mijn praktijksituatie dat de meeste "gaten" in JUnit stiekem best aardig kunnen, als je maar een beetje creatief met het framework bent.
Tja.. in de praktijk merk ik dat ik bepaalde tests niet goed herbruikbaar maak (bv interface tests). En verder zijn er nog een paar dingen die mij dagelijks storen.
Ze zijn er dus weer mee bezig.
Gelukkig.. (werd ook wel een keer tijd)

[ Voor 12% gewijzigd door Alarmnummer op 25-05-2005 13:36 ]

Pagina: 1