[PHP5] Exceptions - doorgaan met try na een throw?

Pagina: 1
Acties:

  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
Ik ben bezig met het schrijven van een (redelijk) uitgebreide applicatie in PHP5 (OO). Een onderdeel van de applicatie is de O/R-conversie (welke PHP-objecten omzet naar (relationele) databaserecords en v.v.). Ik heb besloten om gebruik te maken van unittesting (PHPunit) om deze O/R-klassen te testen.

Nu heb ik in de O/R-klassen gebruik gemaakt van Exceptions (throw - try/catch). Het probleem met de unittests is dat deze het (uiteraard) prima deden voordat er Exception-handling in zat, maar nu er de try/catch-statements zijn ingevoerd, geeft m'n foutafhandeling netjes een foutmelding terug als er vanuit de O/R-klassen een Exception gethrowd wordt. Heel mooi, maar daardoor stopt uiteraard de unittesting ook meteen, aangezien er naar de catch wordt gesprongen.

Mijn vraag is de volgende: is het mogelijk om na een try/catch door te gaan met de try-code (of beter gezegd: door te gaan met de unittesting) nadat een Exception is gethrowd? Zoals wel te begrijpen is heb ik geen zin om overal de throw's eruit te halen, en om een surrogaat-Exceptionklasse te maken helpt niet (hij zit eenmaal in de catch na het throwen, dus teruggaan naar de rest van de try-statements werkt niet).

Ik ben op de hoogte van het feit dat er een finally-statement bestaat, maar deze is niet bruikbaar in deze situatie, aangezien er een flink aantal testcases worden uitgevoerd die stuk voor stuk een Exception zouden kunnen teruggooien.

Iemand ideeën/suggesties of wellicht een andere aanpak van de unittesting?

Dingen die ik al geprobeerd heb:
- bovengenoemde surrogaat-exceptionklasse gemaakt
- een return in de catch (ja, ik weet het, 't is onlogisch, maar was te proberen)

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 18:46

Gerco

Professional Newbie

Maak 1 functie per testcase en laat die functies aanroepen door een overkoepelende functie die een exception gewoon als een gefaalde test beschouwd. Misschien snap ik het probleem niet, maar dit lijkt me een oplossing.

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
Gerco schreef op vrijdag 15 april 2005 @ 14:32:
Maak 1 functie per testcase en laat die functies aanroepen door een overkoepelende functie die een exception gewoon als een gefaalde test beschouwd. Misschien snap ik het probleem niet, maar dit lijkt me een oplossing.
Een dergelijke constructie is er al. Alle testsuites (1 testsuite test alle methoden voor 1 O/R-klasse) worden centraal geïnitieerd. Indien er ook maar 1 testcase in zo'n testsuite mislukt, wordt de uitvoer van de unittest voor die bepaalde testsuite afgebroken en wordt de fout afgevangen. Het probleem blijft echter bestaan: als je in een testsuite 10 testcases hebt staan, en bij #3 gaat het mis, worden #4-#10 niet meer uitgevoerd, terwijl dit wel de bedoeling was (en dat ook gewoon werkte zonder de exceptionhandling).

Het is mogelijk om 1 testcase per testsuite te maken, maar dat is vanuit unittesting-oogpunt onjuist en daarnaast ook nog eens ontzettend omslachtig.

  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21

tombo_inc

uhuh

je moet denk ik je try/catch blokken kleiner maken. alle code die na een throw (tot de eerste catch) komt word niet meer uitgevoerd. de code die na een catch blok komt wel. als je je try/catch blokken dus kleiner maakt heb je meer code die erna word uitgevoerd. wat idd vervelend is is dat je dieperliggende code niet meer uitgevoerd wordt. ik weet ook niet wat je daaraan kan doen.

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Er hoort ook geen exception te komen natuurlijk. Als je dat verwacht in een specifieke test, dan moet je daar ook expliciet rekening mee houden lijkt me?
Krijg je ergens een onverwachte exception, dan heb je een fout gevonden. In andere gevallen die fout gaan wordt dan de test afgebroken of niet? Met een exception heb je over het algemeen geen goed fatsoenlijke state meer in je objecten en wordt het doorgaan met testen er niet beter op, lijkt me.

  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
ACM schreef op vrijdag 15 april 2005 @ 15:05:
Er hoort ook geen exception te komen natuurlijk. Als je dat verwacht in een specifieke test, dan moet je daar ook expliciet rekening mee houden lijkt me?
Krijg je ergens een onverwachte exception, dan heb je een fout gevonden. In andere gevallen die fout gaan wordt dan de test afgebroken of niet? Met een exception heb je over het algemeen geen goed fatsoenlijke state meer in je objecten en wordt het doorgaan met testen er niet beter op, lijkt me.
In principe zijn alle exceptions die vanuit de O/R-klassen worden gethrowd 'verwachte' exceptions. Voorbeeldje: ik heb een klasse Page, als ik daarvan de constructor aanroep met een ID als parameter, dan probeert-ie de desbetreffende Page uit de Page-tabel in de DB op te zoeken. Het kan voorkomen dat ik een ongeldige ID opgeef (wat ik dus met opzet uitprobeer bij een testcase), en het is dan de bedoeling dat ik een fout terugkrijg dat het niet gelukt is. Het is echter niet de bedoeling dat-ie stopt met de testcases, hij moet bijv. alleen teruggeven dat er een throw is uitgevoerd, en dat-ie dat de errorcode ophaalt voor verder gebriuk in een resultstabel (waar alle resultaten van de testsuites worden weergegeven).

Als het object daadwerkelijk gaat gebruikt worden (dus niet voor unittesting, maar voor in productie), dán hoort-ie wel een exception terug te geven met bijbehorende exceptionhandling. Het is alleen de bedoeling dat-ie tijdens de unittesting alleen bijv. de exception-instantie teruggeeft, dat de unittest er vervolgens de gewenste gegevens uithaalt (bijv. wat is de foutcode?) en vervolgens rustig verder gaat met de testcases (en dus niet verder gaat met de volgende testsuite).

En wat betreft de states: bij elk testcase (tot nu toe) wordt er opnieuw een object aangemaakt van de betreffende klasse die getest wordt, dus volgens mij heb je dan geen last van state-loss. Bij de testcases die ik nu heb geschreven, worden tot dusver alleen de constructors getest.

Ik hoop dat ik het zo duidelijk heb verwoord.

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 18:46

Gerco

Professional Newbie

Als je wilt testen of er een bepaalde exception uit je object komt, moet je die exception natuurlijk IN je testcase opvangen en de testcase laten falen als die exception NIET komt. De meeste unit test frameworks hebben wel 1 of andere AssertException BlaBlaException voor die faalt als die exception niet optreed.

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
Gerco schreef op vrijdag 15 april 2005 @ 15:50:
Als je wilt testen of er een bepaalde exception uit je object komt, moet je die exception natuurlijk IN je testcase opvangen en de testcase laten falen als die exception NIET komt. De meeste unit test frameworks hebben wel 1 of andere AssertException BlaBlaException voor die faalt als die exception niet optreed.
Jouw reactie heeft me op een idee gebracht. Wat zou er gebeuren als ik in de unittesting-framework, precies op de plek waar m'n testcase wordt uitgevoerd, een try-catch plaats, waarbij de catch een PHPunit-native 'fail'-message terugstuurt met daarbij m'n eigen errorcode van de gethrowde exception? (retorische vraag). Ik ben dit nu aan het uitproberen, de eerste resultaten zijn hoopvol. :)

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 04-05 14:55

Janoz

Moderator Devschuur®

!litemod

Wat is er eigenlijk mis met de volgende code?
Java:
1
2
3
4
5
6
7
8
9
10
      try
      {
         ActionInvokerHelper.convertParameter(parameter);

         fail("This conversion should have thrown an exception, but it didn't");
      }
      catch (Exception e)
      {
         assertTrue(true);
      }

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
Janoz schreef op vrijdag 15 april 2005 @ 16:13:
Wat is er eigenlijk mis met de volgende code?
Java:
1
2
3
4
5
6
7
8
9
10
      try
      {
         ActionInvokerHelper.convertParameter(parameter);

         fail("This conversion should have thrown an exception, but it didn't");
      }
      catch (Exception e)
      {
         assertTrue(true);
      }
In principe is dit ook de manier waarop het moet, maar dan zou het unittest-framework ondersteuning moeten bieden voor exceptions (dus iets met $this->assertException("ERRORCODE"), waarbij de meegegeven parameter de "verwachte" exception bevat). Helaas ben ik er achter gekomen dat PHPunit dat niet ondersteunt, dus zal ik een andere manier moeten vinden.

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

dennisvz schreef op vrijdag 15 april 2005 @ 16:32:
In principe is dit ook de manier waarop het moet, maar dan zou het unittest-framework ondersteuning moeten bieden voor exceptions (dus iets met $this->assertException("ERRORCODE"), waarbij de meegegeven parameter de "verwachte" exception bevat). Helaas ben ik er achter gekomen dat PHPunit dat niet ondersteunt, dus zal ik een andere manier moeten vinden.
Bovenstaande kan je toch zelf als testcode gebruiken? In Janoz' voorbeeld wordt geen exception omhoog gegooid naar je unit test framework.

  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
ACM schreef op vrijdag 15 april 2005 @ 18:04:
[...]

Bovenstaande kan je toch zelf als testcode gebruiken? In Janoz' voorbeeld wordt geen exception omhoog gegooid naar je unit test framework.
Dat klopt, maar dan kun je ook niet aangeven dat je juist een bepaalde exception verwacht. Oké, je kunt in de catch controleren of de meegekregen exception de verwachte errorcode bevat, maar imho worden de testcases hierdoor 'lomper' dan eigenlijk m'n bedoeling was.

Wat ik wilde was een simpele manier om te zeggen dat ik een bepaalde exception verwacht tijdens de uitvoer van een testcase, dus iets van
PHP:
1
$this->assertException("MIJN_ERRORCODE");


Als je dit niet op deze manier doet, moet je zowel in de try-clausule op het eind ('ik verwachtte die en die exception, maar kreeg er geen') als in de catch-clausule ('ik kreeg een exception, maar is deze ook van het type die ik verwachtte?') zetten. Dat is eigenlijk niet m'n bedoeling.

Verwijderd

Kwestie van zelf een assertThrows schrijven, zoiets dergelijks:

code:
1
2
3
4
5
6
7
8
function assertThrows($code, $exception) {
    try {
        exec($code);
        assert false;
    } except(Exception $e) {
            assert $e van type $expception;
    }
}

  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
Verwijderd schreef op zaterdag 16 april 2005 @ 15:01:
Kwestie van zelf een assertThrows schrijven, zoiets dergelijks:

code:
1
2
3
4
5
6
7
8
function assertThrows($code, $exception) {
    try {
        exec($code);
        assert false;
    } except(Exception $e) {
            assert $e van type $expception;
    }
}
Klopt, ik ben nu zelf ook bezig om een assertException (zoals jij ook suggereert) te schrijven. Dit lijkt mij op dit moment het beste.

  • Martin Sturm
  • Registratie: December 1999
  • Laatst online: 30-04 16:11
Als je hem dan ook nog upstream submit, dus mailit naar het PEAR project, dan hebben andere er ook nog wat aan.

  • dennisvz
  • Registratie: Mei 2003
  • Laatst online: 24-02 12:08

dennisvz

Intentionally left blank

Topicstarter
Martin Sturm schreef op zondag 17 april 2005 @ 10:54:
Als je hem dan ook nog upstream submit, dus mailit naar het PEAR project, dan hebben andere er ook nog wat aan.
Denk ook wel dat ik het ga doen. PHPUnit is onderdeel van het PEAR-project, dus waarom niet?
Pagina: 1