.
Anmeldung | Registrieren | Hilfe
in Suchen

TDD und CodeContracts: ExpectedException funktioniert damit nicht

Letzter Beitrag 13. Okt 2009 16:14 von Timo Rehl. 10 Antworten.
Seite 1 von 1 (11 Treffer)
Beiträge sortieren: Zurück Weiter
  • 11. Okt 2009 23:00

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 927
    • Punkte 14.105

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Hallo,
    ich schreibe gerade Unit Tests für Methoden die unter CodeContracts stehen.

    [ExpectedException(typeof(ContractException))]

    kann leider nicht angegeben werden weil die ContractException internal ist.
    weiß jemand eine Alternative?

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 12. Okt 2009 9:00 Antwort zu

    • Timo Rehl
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 05. Mai 2009
    • Wald-Michelbach
    • Beiträge 591
    • Punkte 10.110
    • Moderator

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Hallo Rainer,

    ich weiß leider keine Alternative, aber ich habe die Lösung Stick out tongue

    The Automated Tester - NUnit internal classes
    Stichwort: MSDN - InternalsVisibleToAttribute

    Viele Grüße
    Timo
    - theres no place like 127.0.0.1 -
    • IP-Adresse ist Registriert
  • 12. Okt 2009 10:16 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 927
    • Punkte 14.105

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Hallo Timo,
    das geht leider nicht, denn dafür müßte ich das InternalsVisibleTo Attribut in die AssemblyInfo der CodeContracts-Library einsetzen, aber die steht mir nicht zur Verfügung. Stick out tongue
    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 12. Okt 2009 10:31 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 927
    • Punkte 14.105

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Ich benutze jetzt einen WorkAround. Es funktioniert, ist aber umständlich und statisch.

    1. In der Testklasse abonniere ich das ContractFailed Event.

    [AssemblyInitialize]
    public static void AssemblyInitialize(TestContext tc)
    {
       Contract.ContractFailed += OnContractFailed;
    }

    2. Ich definiere eine klassenweite Hilfsvariable vom Typ ContractFailedEventArgs.

    private static ContractFailedEventArgs contractFailedEventArgs;

    3. Ich schreibe folgenden EventHandler:

          static void OnContractFailed(object sender, ContractFailedEventArgs e)
          {
             e.SetHandled();
             contractFailedEventArgs = e;
             Console.WriteLine(e.Condition + ": " + e.Message);
          }

    4. Die Exception-Message, die an die Hilfsvariable übergeben wurde, kann im Test mit einem Sollwert verglichen werden.

          [TestMethod]
          public void EnsuresAndResultDemoTest()
          {
             var target = new SomeClass();
             int someValue = 2;
             target.EnsuresAndResultDemo(someValue);
             Assert.AreEqual("Postcondition failed: Contract.Result<double>() >= 10",
                contractFailedEventArgs.Message);
          }

    Dieser letzte Schritt ist das umständliche und unflexible an der Sache. Um den Sollwert zu ermitteln, muß ich den Test erst einmal "nackt" laufen lassen, um zu erfahren wie genau die Exception Message denn lautet. Die kopiere ich mir dann in den Assert. Ziemlich blöde Sache. Huh?

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 12. Okt 2009 14:45 Antwort zu

    • Timo Rehl
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 05. Mai 2009
    • Wald-Michelbach
    • Beiträge 591
    • Punkte 10.110
    • Moderator

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Hallo Rainer,

    ok, ok, ich geb mich geschlagen, wenn Du auf die Contracts keinen Einfluss hast?! Stick out tongue Stick out tongue

    -> Naja da fällt mir in der Tat nur Reflection ein, was aber auch nur dann funktioniert, wenn die Struktur es vorgibt (z.B. alle internal Exception-Klassen haben im Namen "Exception").
    Der Workaround ist wirklich ein wenig hässlich.

    Andere Frage:
    Kannst Du im Test nicht eine "System.Exception" erwarten, und dann anhand dessen Namen bestimmen, ob die richtige Exception geschmissen wurde (ok, auch hässlich, aber kürzer als Dein Workaround)?

    Grüße
    Timo
    - theres no place like 127.0.0.1 -
    • IP-Adresse ist Registriert
  • 12. Okt 2009 15:36 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 927
    • Punkte 14.105

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Antworten

    Hallo Timo,
    ExpectedException(typeof(Exception)) geht nicht. Es kommt zu folgender Fehlermeldung:

    UTA017: ContractTests.SomeClassTest.EnsuresAndResultDemoTest has invalid ExpectedException attribute. The type must inherit from Exception.

    Ich denke das ist "by Design", denn so wie man bei einem Try/Catch-Block nach Möglichkeit spezifische Exceptions abfangen soll, ist es auch bei Unit Tests angebracht.
    Du hast mir aber den Schubs in die korrekte Richtung gegeben. Der Test sieht jetzt so aus und macht was er soll:

          public void EnsuresAndResultDemoTest()
          {
             var target = new SomeClass();
             int someValue = 2;
             try
             {
                target.EnsuresAndResultDemo(someValue);
             }
             catch(Exception exc)
             {
                Console.WriteLine(exc.GetType().Name);
                Assert.IsTrue(exc.GetType().Name == "ContractException");
                return;
             }
             Assert.Fail("ContractException has not been thrown.");
          }

    Weil SetHandled das Werfen der ContractException abstellt, muß nur der EventHandler leicht modifiziert werden.

          static void OnContractFailed(object sender, ContractFailedEventArgs e)
          {
             e.SetHandled();
             Console.WriteLine(e.Condition + ": " + e.Message);
             e.SetUnwind();
          }

    Mit SetUnwind wird die Exception wieder geworfen.

    Ich hab mal irgendwo gelesen daß Try/Catch in einer Testmethode vermieden werden sollte (eben auch weil es ein Zeichen für unwägbaren code under test ist), aber das hier könnte ein Ausnahmefall sein.

    Falls du CodeContracts nicht kennst, schau dir das API mal an, ist ne tolle Sache.
    CodeContracts

    Ausführlicher hier:
    CodeContracts

    Es gibt zwei kommerzielle Lizenzen und eine freie akademische, die aber ziemlich versteckt ist. Darum hier ein Extra-Link.

    Download der freien academic version mit static checker.

    CodeContracts ist auch im .net Framework 4 enthalten.

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 12. Okt 2009 16:27 Antwort zu

    • Timo Rehl
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 05. Mai 2009
    • Wald-Michelbach
    • Beiträge 591
    • Punkte 10.110
    • Moderator

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Antworten
    Hallo Rainer nochmal,

    Falls du CodeContracts nicht kennst

    Ja und nein. Ich kenne das Prinzip von CodeContracts, allerdings wusste ich nicht, dass da was im FW 4.0 von Microsoft kommt. Bisher habe ich nur Custom-Umsetzungen oder Third-Party hierzu gefunden/verwendet.

    Insofern: vielen Dank für die Informativen Links.

    Übrigens hatte ich insgeheim eine "Try-Catch" Verwendung gemeint (ich hatte es allerdings nicht direkt erwähnt). Ich denke, dass "Try-Catch" hier in NUnits vertretbar ist. Wir im Projekt verwenden dieses Konstrukt sogar recht häufig, z.b. auch um allgemeine Runtime-Exceptions wie z.B. "Datenbank aktuell nicht erreichbar" abzufangen. Dann kann man nämlich eine eigene Exception über NUnit ausgeben lassen, die z.B. wie folgt aussieht: "Konnte Methode xyz nicht erfolgreich testen, weil DB Kaputt Big Smile!"

    Grüße
    Timo
    - theres no place like 127.0.0.1 -
    • IP-Adresse ist Registriert
  • 13. Okt 2009 1:18 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 927
    • Punkte 14.105

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Timo Rehl:
    z.b. auch um allgemeine Runtime-Exceptions wie z.B. "Datenbank aktuell nicht erreichbar" abzufangen. Dann kann man nämlich eine eigene Exception über NUnit ausgeben lassen, die z.B. wie folgt aussieht: "Konnte Methode xyz nicht erfolgreich testen, weil DB Kaputt Big Smile!"

    Das macht Sinn. Yes

    Ich habe aus der Lösung kurzerhand ein Snippet gebastelt. Vielleicht kann es anderen auch behilflich sein.

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 13. Okt 2009 7:25 Antwort zu

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Unter den NUnit Extensions (oder ist es mittlerweile schon mit drinnen) gibt es einen Funktion die nennt sich Assert.Throws(...) die genau das macht ;-)

    unter den anderen Testframeworks gibt es glaube ich ähnliche Methoden. Bei xUnit.BDDextensions ist es ShouldThrow(..)
    • IP-Adresse ist Registriert
  • 13. Okt 2009 13:08 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 927
    • Punkte 14.105

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Ich benutze Gallio - habe gerade mal nachgeschaut, MBUnit hat auch Assert.Throws im Gepäck. Allerdings erwartet die Methode, wie sollte es auch anders sein, den Typ der Exception. Damit steht man als Entwickler wieder vor dem gleichen Dillema wie bei dem ExpectedException-Attribut von MSTest.
    Ich verstehe nicht, warum Microsoft die ContractException-Klasse internal gemacht hat. Hoffentlich ist das in der .net 4 Version anders.
    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 13. Okt 2009 16:14 Antwort zu

    • Timo Rehl
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 05. Mai 2009
    • Wald-Michelbach
    • Beiträge 591
    • Punkte 10.110
    • Moderator

    TDD und CodeContracts: ExpectedException funktioniert damit nicht

    Hallo zusammen,

    Ich verstehe nicht, warum Microsoft die ContractException-Klasse internal gemacht hat.

    Das verstehe ich in der Tat auch nicht. Gerade Exceptions sind "global" handzuhaben. Irgendwo kommen die Exceptions doch durchgedrungen, und dann sollte man auch Zugriff darauf haben.
    Hier würde ich das auch als Designfehler sehen, das ist meiner Meinung nach der falsche Weg von Kapselung.

    Grüße
    Timo

    - theres no place like 127.0.0.1 -
    • IP-Adresse ist Registriert
Seite 1 von 1 (11 Treffer)

WPF Forum | ASP.NET Forum | ASP.NET MVC Forum | Silverlight Forum | Windows Phone 7 Forum | SharePoint Forum | Dotnet Jobs | Dotnet Termine | Developer Blogs | Dotnet News

Das Team | Regeln | Impressum