Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von N1ls
Thema: Rückgabetyp = Typ der aktuellen Klasse: ohne Generics?
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Zitat von Gandi
@N1ls: Was genau meinst du? Das mit dem statischen "Create" oder dass die Syntax dafür möglichst kurz sein soll? Für das "Create" habe ich jedenfalls einen praktischen Nutzen, ist allerdings etwas aufwändiger zum erklären. Und Delphi kann ich auf jeden Fall mal nicht^^

Ich meine eher das statische Create. Kurz wird's ja schon, wenn ich nur


A myA = new A()

schreibe.

Konstruktoren sind eh statisch. Also wieso diese Umständlichkeiten?

Grüsse,

N1ls

Thema: Rückgabetyp = Typ der aktuellen Klasse: ohne Generics?
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo,

gibt es für soetwas irgendeinen praktischen Nutzen? Tschuldigung, dass ich nachfrage. Aber für mich sieht das irgendwie so aus, als ob Du C# eine Delphi-Syntax aufzwingen willst...

Grüsse,

N1ls

Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Hallo Herbivore,

Zitat von herbivore
Hallo TheBrainiac,

deine Lösung ist korrekt.
...

Hier zum Vergleich noch, wie ich mir das vorgestellt hatte.
...

Ich halte beide Lösungen für relativ schwer lesbar. Wirklich korrekt sind sie auch nicht. Ein Kniffel ist immer auch ein FullHouse, das berücksichtigen beide Varianten nicht. Das lässt sich natürlich einfach korrigieren, steigert aber die Verständlichkeit des Codes nicht wirklich.

MfG,

N1ls

Thema: Delphi 7 dll importieren: Aufruf von Methode aus DLL lässt Anwendung ohne Exception festhängen
Am im Forum: Rund um die Programmierung

Zitat von Spook
Das ist Unsinn. StringBuilder dient bei Plattformaufrufen als beschreibbarer Puffer. [...]
Wenn du eine konstante Zeichenkette als Parameter übergibst oder als Rückgabewert bekommst kann dieser als string deklariert werden.

Wenn das so unsinnig ist, wäre es ja schön gewesen, Du hättest auch mal ein entsprechendes Beispiel mit einem String-Rückgabewert aufgeführt.

MfG,

N1ls

Thema: Delphi 7 dll importieren: Aufruf von Methode aus DLL lässt Anwendung ohne Exception festhängen
Am im Forum: Rund um die Programmierung

Hallo And.Wolf,

[DllImport("mydll.dll", SetLastError = true,CharSet = CharSet.Ansi)]
private static extern StringBuilder MyFunction(string Par);

versuch es mal so. Hab's jetzt nicht ausprobiert. Ich weiss auf jeden Fall, dass Du einmal den Stringbuilder für den Rückgabewert nutzen musst, einen einfachen String für den Übergabeparameter. Klingt erstmal komisch, ist aber so ;-)

Evtl. musst Du noch die Calling Convention im Delphi Code auf StdCall anpassen.

Grüsse,

N1ls

Thema: Tatsächlicher Nutzen von Unit-Tests [und TDD]
Am im Forum: Rund um die Programmierung

Hallo CSL,

Zitat von CSL
Wenn man erst die UI macht besteht aber die Gefahr das man u.u:
- "mal eben" eine Funktionalität ein hackt,
- das man UnitTests weg lässt um die UI "schnell mal eben" mit Funktionalität aus zu statten,
- das man weniger Abstrahiert sondern direkt mit der UI verknüpft (Ruf die Komponente einfach mal schnell auf()

Da gebe ich Dir vollkommen Recht. Dazu gehört dann natürlich Disziplin und sicherlich auch Überzeugungsarbeit bei so manchem Chef, um gegen diese Gefahren zu arbeiten. Aber das ist doch auch ein Stück, worauf man hinaus will, wenn man Test-Driven entwickeln als sinnvoll ansieht, oder?
Das UI steht, es ist bekannt welche TextEdits es gibt, welche Checkboxen, Radiobuttons etc. Jetzt kann man an die Logik des UI gehen und diese Test-Driven entwickeln - quasi per Unit-Tests Stück für Stück das Klasse aufbauen, die die Logik des UI widerspiegelt.
Zitat
- das man Dummy Templates erstellt die die Funktionalität erst viel Später bekommen (wichtige Zeit verloren),

Man muss ja nicht zwangsweise das komplette UI sofort erstellen. Wenn sich Teile sinnvoll abgrenzen lassen, kann man da sicherlich schrittweise vorgehen.
Zitat
- und zu guter letzt das man die UI immer wieder umbauen muss da sich bei der Implementation der Funktionalität neue Erkenntnisse ergaben.

Genau das bezweifel ich. Das UI entwickele ich nach den Anforderungen und Wünschen des Kunden. Wenn dieser damit zufrieden ist, dann interessiert ihn nicht mehr, was dahinter liegt. Wenn bei der Implementierung der Funktionalitäten dann Probleme auftauchen, heisst das entsprechend, ich kann Anforderungen respektive Wünschen nicht mehr gerecht werden. Dann habe ich aber ein ganz anderes Problem als den Umbau des UI. Das sollte aber der Ausnahmefall sein.

Grüsse,

N1ls

Thema: Tatsächlicher Nutzen von Unit-Tests [und TDD]
Am im Forum: Rund um die Programmierung

Hallo herbivore,

Zitat von herbivore
Zitat
Alleine die Auffassung "nur noch eine UI davor packen" widerspricht jeglichen agilen Prinzipien. Und TDD kommt nun einmal aus genau dieser Richtung.
TDD sagt erstmal nichts darüber aus, ob man Top-Down oder Bottom-Up entwickelt. Es sagt nur, dass du den Test vor der Implementierung schreibst.

Ich habe nicht behauptet, dass TDD eine Richtung vorgibt. Es kommt aber aus der agilen Softwareentwicklung und dort geht es u.A. darum kontinuierlich Nutzen zu produzieren. Das kann ich eben nicht, wenn ich zuerst mit TDD das komplette Backend fertige und dann das UI anfange. Im schlimmsten Falle ist Release-Termin, wenn ich mit dem Backend gerade durch bin... das heisst dann, ich habe noch überhaupt keine Funktionalität geschaffen, jedenfalls keine für den Kunden nutzbare.
Zitat
Gerade wenn du sagst, dass bei der Entwicklung "vom User Interface in Richtung Backend" "seltener nachträgliche Änderungen gewünscht werden", bedeutet das doch, dass das das gewünschte Verhalten (gerade auf den oberen, gui-nahen Ebenen) von Anfang an feststeht (und sich nicht mehr ändert). Das sind doch optimale Voraussetzungen, um dieses Verhalten in Forms von Tests auszudrücken und damit auch zu fixieren. Also nochmal, nur weil du TDD verwendest, musst du nicht Bottom-Up arbeiten.

Das ist ja genau meine Meinung. Und so gehe ich bzw. versuche ich möglichst vorzugehen. Deshalb finde ich es auch Schade in Bezug auf TDD etwas zu lesen wie
Zitat
Man löst Probleme auch von der anderen Richtung, ich für mein Fall hatte oft mit der UI angefangen und dann stück für stück zur Funktionalität vor gearbeitet. Jetzt erstell ich erst die Funktionalität und muss dann nur noch eine UI davor packen.

Bei mir hat sich dieses Bewusstsein, immer vom UI aus zu arbeiten, eigentlich letztes Jahr auf der Advanced Developers Conference gefestigt. In bestimmt 4 oder 5 der von mir besuchten Sessions wurde genau dieses Vorgehen empfohlen, ebenso im anschliessenden Workshop mit Ralf Westphal. Gegenteilige Meinungen habe ich nicht mitbekommen.
Genau daran denke ich jetzt immer, wenn ich von Kollegen höre "das können wir jetzt nicht so einfach ändern, dann müsste ich das ganze Backend umstellen". Dieser Satz taucht immer auf, wenn man dem Kunden zum ersten Mal das UI vorstellt...

Grüsse,

N1ls

Thema: Tatsächlicher Nutzen von Unit-Tests [und TDD]
Am im Forum: Rund um die Programmierung

Zitat von CSL
Man löst Probleme auch von der anderen Richtung, ich für mein Fall hatte oft mit der UI angefangen und dann stück für stück zur Funktionalität vor gearbeitet. Jetzt erstell ich erst die Funktionalität und muss dann nur noch eine UI davor packen.

Wenn TDD zu einem solchen Verhalten führt, dann werden dadurch natürlich erhebliche Mehrkosten verursacht. Entwicklung vom User Interface in Richtung Backend ist effizient, weil
  • keine Funktionalität implementiert wird, die nicht benötigt wird
  • seltener nachträgliche Änderungen gewünscht werden(wenn das UI vom Kunden abgenommen ist, man im Backend relativ frei)

Alleine die Auffassung "nur noch eine UI davor packen" widerspricht jeglichen agilen Prinzipien. Und TDD kommt nun einmal aus genau dieser Richtung.

Von daher finde ich es natürlich falsch, hier im Thread zu suggerieren, TDD wuerde die Entwicklungsweise in dieser Hinsicht quasi umkehren.
Zitat von CSL
Da ist eben der unterschied, unser Vor/Zurück hat keine Logik die ein Button deaktiviert oder ähnliches, ...

Genau DAS meinte ich. Wenn keine Logik, dann ist es sinnlos mit Vor- und Zurück-Buttons zu arbeiten. Mindestanforderung, um soetwas einem TabControl vorzuziehen ist eine notwendige Sequenz.
Zitat
Ich würde aber vor schlagen das Thema hier sein zu lassen, da das nicht mehr zum Thema gehört.

Ich denke diese gehört eng zusammen(wieso sonst sollte es hier aufgetaucht sein?). Der Nutzen von Unit-Test hängt auch mit dem Verständnis von verschiedenen Controls zusammen. Ich muss zum Teil die Business-Logik aus diesen Controls rausziehen, um wirklichen Nutzen aus TDD oder überhaupt Unit-Tests ziehen zu können.

MfG,

N1ls

Thema: UnitTests: Strukturierung und Bennenung der Tests/Testprojekte/Testmethoden
Am im Forum: Rund um die Programmierung

Zitat von CSL
Wie wär es damit, gerade gefunden in mein TDD Material:

[TestMethod]
public void Plus_FileDollarPlusFiveDollar_ReturnsSumExpression()
{
	Money five = Money.Dollar(5);
	Money six = Money.Dollar(6);

	IExpression result = five.Plus(six);
	Sum sum = (Sum)result;

	Assert.AreEqual(five, sum.Augend);
	Assert.AreEqual(six, sum.Addend);
}

"Sum" ist eine Expression die die beiden Zahlenwerte enthält, hier wurde überprüft das "Plus" korrekt "Sum" erstellt hat.
Das in zwei Tests wäre schon recht absurd.

Das wäre schonmal ein Beispiel, wo der Testname nicht passt("Plus_FiveDollarPlusSixDollar_ReturnsSumExpression" <- mal die vertipper direkt bereinigt). Ein Test für diesen Testnamen müsste ja eigentlich folgendermassen aussehen:


public void Plus_FiveDollarPlusSixDollar_ReturnsSumExpression()
{
	Money five = Money.Dollar(5);
	Money six = Money.Dollar(6);

	IExpression result = five.Plus(six);

	Assert.IsTrue(result is Sum);
}

Das finde ich erstens einen guten Test, um sicherzustellen, dass das IExpression, was von der Plus-Methode zurückgeliefert wird, wirklich vom Typ Sum ist und zweitens prüft der Test nun genau das, was in seinem Namen steckt.

Aber wie weiter? Kommutativgesetz lassen wir mal aussen vor. Nehmen wir an, die Reihenfolge der Summanden wäre wichtig. Dann käme ich zu dem Testnamen "Plus_FiveDollarPlusSixDollar_ReturnsSumWithAugendFiveAndAddendSix". Das "And" macht mir da wieder Sorgen. Was würde es bedeuten, dies wirklich wieder auf 2 Tests aufzusplitten?


private Sum GetSumAddFiveDollarAndSixDollar()
{
	Money five = Money.Dollar(5);
	Money six = Money.Dollar(6);

	return (Sum)(five.Plus(six));
}

public void Plus_FiveDollarPlusSixDollar_SumWithAugendFive()
{
        Sum s = GetSumAddFiveDollarAndSixDollar();

        Assert.AreEqual(5, s.Augend);
}

public void Plus_FiveDollarPlusSixDollar_SumWithAddendSix()
{
        Sum s = GetSumAddFiveDollarAndSixDollar();

        Assert.AreEqual(5, s.Addend);
}

Jetzt wird eigentlich auch klar, dass die Prüfung auf ein Sum-Objekt bei der Plus-Methode gar nicht mehr notwendig ist(man könnte sie dennoch beibehalten), dies wird implizit mitgeprüft.

Ist das jetzt wirklich absurd, daraus 2 Testcases zu machen? Ich prüfe auf jeden Fall auch zwei unterschiedliche Dinge: Die Werte und deren Reihenfolge.
Zitat
Dazu fällt mir etwas ein, habe ich gerade in einem Projekt gesehen.

Ich bekomme von einer Methode eine Liste von Dokumenten, die Dokumente wiederum haben eine Liste von Sprachen.
Ich muss prüfen das die Sprachen alle korrekt sind, also Gültige Sprachen.
Ich hatte zu dem Zweck einfach die Dokumente geloop und in dem loop das Assert per Linq auf die Sprach liste los gelassen.
Wie würde man so etwas korrekt Testen?

Dann bewegen wir uns schon gar nicht mehr im Bereich von Unit-Tests. Das sind Integrationstests. ;-)

MfG,

N1ls

Thema: UnitTests: Strukturierung und Bennenung der Tests/Testprojekte/Testmethoden
Am im Forum: Rund um die Programmierung

Zitat von gfoidl
Hallo CSL,

ich würds wie weiter oben geschrieben halten:
Zitat von dN!3L
Oder mit R. Osheroves Worten: "Wenn du Probleme hast, einen Test zu benennen, testet er zu viel".

Das ist sicherlich ein gutes Kriterium, alleine aber zu wenig. Gerade bei Anfängern in Sachen Unit-Tests merke ich häufig, dass diese überhaupt keine Probleme haben einen Namen für einen Test zu finden. Beispielsweise finde ich da bei einem Stack Testmethoden a la "TestPushElement". Das sieht für einen Anfänger total unproblematisch und nach einem guten Namen aus. Und innerhalb solcher Tests wird dann natürlich auf alles, was sich bewegt, mit Asserts geschossen.

Voraussetzung ist also m.E. nach erstmal, dass es Namenskonventionen für Tests gibt. Darin muss sich inhaltlich wiederspiegeln, was getan wird und was erwartet wird. Erst dann lässt sich obiges Kriterium sinnvoll anwenden.

Aber es ist irgendwie immer noch nicht ausreichend. Bleiben wir mal beim Stack:


public Push_OneElement_ElementIsTopElementOnTheStack()
{
    // Arrange
    var sut = new Stack<int>();
    
    // Act
    sut.Push(2);

    // Assert
    Assert.AreEqual(1, sut.Count);
    Assert.AreEqual(2, sut.Peek());
}

So (ähnlich) hätte ich das bis vor kurzem als Test implementiert. Ich hatte auch kein Problem damit, einen Namen für den Test zu finden. Dennoch würde ich heute sagen, es wird eindeutig zuviel getestet.
Was würde jetzt passieren, wenn im Code jedes Element versehentlich doppelt auf dem Stack landet? Der Test würde fehlschlagen mit der Meldung, dass 1 erwartet wurde, jedoch der tatsächliche Wert 2 ist. Hier wird schon deutlich, dass ich mir die optionalen Meldungen der Asserts nicht mehr sparen kann, wenn ich mehrere innerhalb eines Tests habe.
Viel schlimmer aber noch ist, dass ich hier im Testprotokoll quasi belogen werde. Wenn der Test fehlschlägt, heisst das die Erwartung "ElementIsTopElementOnTheStack" ist nicht erfüllt. Stimmt aber nicht, das oberste Element entspricht nämlich dem hinzugefügten Element.

Vielleicht ist das nicht für jeden (sofort) nachvollziehbar, aber ich fühle mich da mittlerweile mit einem extra Test "Push_OneElement_ElementCountIncreasesByOne" bedeutend besser.
Und beim Durchschauen meiner Tests geht mir das irgendwie bei jedem Test so, der mehr als ein Assert enthält. Entweder komme ich zu dem Schluss, die getesteten Dinge sind zu unterschiedlich, um in einen Test zu gehören(hier die Größe des Stacks und der Inhalt des Stacks), oder ich bin nicht damit zufrieden, wie sich das im Protokoll der Testausführung liest.

Ich bin immer noch nicht an dem Punkt, dass ich mehr als ein Assert per se verteufeln würde. Aber da müssen schon wirklich gute Gründe sprechen. Wäre schön, wenn hier jemand mal ein Beispiel hätte, wo man partout nicht ohne mehrere Asserts auskommt.

MfG,

N1ls

Thema: UnitTests: Strukturierung und Bennenung der Tests/Testprojekte/Testmethoden
Am im Forum: Rund um die Programmierung

Zitat von CSL
user name und passwort könnte auch mit übergeben werden, da es aber immer das selbe ist hab ich es weg gelassen.
Was meint ihr?

Ich würde es auch nicht übergeben. Jedoch würde ich wahrscheinlich die Methode eher "CreateSessionUsingValidCredentials" nennen. Das wäre eine klare Abgrenzung zu einer evtl. später notwendigen Methode "CreateSessionUsingNotExistingUsername" oder "CreateSessionUsingWrongPassword". Ob man diese braucht, hängt natürlich vom Verhalten des System under Test und den weiteren Tests ab. Man gewinnt aber zumindestens an Klarheit.

Ansonsten: Genau so finde ich die Tests sehr gut lesbar. Besser als mit mehreren Asserts. Und ich habe den Vorteil, dass jetzt alles im Testprotokoll eindeutig festgehalten wird. Man braucht den Testcode nicht mehr. Im Protokoll der ursprünglichen Version sehe ich nur sowas wie
Create_ValidSessionGenerated - Passed

jetzt dagegen:
Create_ValidCredentials_ReturnsWritableSession - Passed
Create_ValidCredentials_ReturnsLoggedInSession - Passed
Create_ValidCredentials_ReturnsMyUserName - Passed

Finde ich zumindest elegant ;-)

MfG,

N1ls

Thema: UnitTests: Strukturierung und Bennenung der Tests/Testprojekte/Testmethoden
Am im Forum: Rund um die Programmierung

Zitat von CSL
Dh ich müsste diese Methode:
...

aufdröseln zu:

...

??

Jein.

1. Ja, ich würde dafür mehrere Tests schreiben.

2. Nein, ich würde (mittlerweile) keinen Test mehr schreiben, der nur überprüft, ob ich überhaupt eine Instanz zurück bekomme. Falls nicht, merke ich das sowieso. Dann schlagen mehrere andere Tests fehl und zwar mit einer NullReferenceException. Ich versuche eigentlich nur noch Verhalten zu testen. Gerade beim Test "Create_UserNameAndPassword_ReturnsSession" ist gar nicht mehr klar, ob die Session oder der SessionCreator einen Fehler hat.

3. Nein, mein Code würde nicht so aussehen. Ich würde das Setup, was in jedem Test gleich ist, in eine Methode auslagern. Wenn sich da mal was ändert, muss man es nur an einer Stelle machen.

4. Nein, ich würde die Methoden nicht so benennen. "Create_UserNameAndPassword_ReturnsLoggedInSession" passt nicht, besser "Create_ValidCredentials_ReturnLoggedInSession".

Ich glaube Haarspalterei kann bei Unit-Tests und insbesondere deren Benamung eine Tugend sein. Der Name eines Tests muss zwingend und möglichst genau dessen Inhalt widerspiegeln. Und der Inhalt ist mehr oder weniger eine Verhlaltensspezifikation. Und dabei ist ein "IsValid" als Erwartungshaltung immer sehr schwammig... daher lieber mehr und konkretere Tests.


Vielleicht noch einmal ergänzend: Mehrere Asserts innerhalb eines Tests finde ich nicht grundsätzlich schlimm. Wenn ich auf zu einer leeren Liste 1 Element hinzufüge, gehe ich davon aus, dass

a.) der Stack genau 1 Element umfasst
b.) genau das Element auf dem Stack liegt, dass ich hinzugefügt habe

Das in 2 Tests aufzuspalten halte ich für unnötig. Zumal der zweite Test eh fehlschlagen wird bzw. nur wenig aufschlussreich ist.

Die Frage ist dabei also, wie sehr die einzelnen Annahmen miteinander gekoppelt sind.

MfG,

N1ls

Thema: UnitTests: Strukturierung und Bennenung der Tests/Testprojekte/Testmethoden
Am im Forum: Rund um die Programmierung

Damit habe ich noch nie Probleme gehabt. Sobald ein Test fehlschlägt, setze ich einen Breakpoint auf die erste Zeile meiner Asserts. Da habe ich im VS dann ja sofort das komplette Objekt auf das ich Teste vollständig unter der Lupe und kann eben die nachfolgenden Asserts am "lebendigen Objekt" auf einen Blick prüfen.

Ich sage nicht, dass das gut ist, aber es wäre halt für mich kein Argument gewesen diese Asserts auf mehrere Tests zu verteilen.

N1ls

Thema: Welchen Vorteil hat die ArgumentNullException zur NullReferenceExcpetion?
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Zitat von Corpsegrinder
Ein Vorteil wäre z.B., dass man direkt sieht, dass ein übergebenes Argument den Wert null hat und nicht innerhalb der für den Benutzer evtl. nicht einsehbaren Klasse ein Fehler ist, der zu einer NullReferenceException führt. Desweiteren kannst du natürlich einen eigenen Text für die Exception angeben und evtl. sogar mitteilen, welcher Parameter null ist usw... Natürlich mach es in diesen Fällen nur Sinn für Debugginginformationen. Vielleicht fallen jemand anderen aber auch noch andere Gründe ein?

Für mich hat das mit Debugging und evtl. Weitergabe besserer Fehlertexte weniger zu tun. Eine ArgumentNullException und eine NullReferenceException haben genau genommen eine vollständig unterschiedliche Qualität:

Auf eine ArgumentNullException kann ich in einem Grossteil der Fälle noch reagieren. Ich weiss nämlich(bzw. hoffe zu wissen), dass von der eigentlichen Aktion die ich mit dem Methodenaufruf erreichen wollte noch überhaupt nichts geschehen ist. D.h. ich bin noch am Ausgangspunkt des Aufrufs... bestenfalls konsistenter Zustand. Bei einer NullReferenceException hingegen kann ich dazu gar keine Annahmen mehr machen. Es kann sein, dass die Festplatte noch gar nicht angerührt wurde, schon halb formatiert oder zu 3/4 formatiert ist. Ich kann weder reagieren noch dem Benutzer eine entsprechende Meldung geben.

Natürlich muss man dabei immer darauf vertrauen, dass kein Unwissender mal eben eine ArgumentNullException wirft, nachdem bereits andere Anweisugen innerhalb einer Methode ausgeführt wurden...

Grüsse,

N1ls

Thema: UnitTests: Strukturierung und Bennenung der Tests/Testprojekte/Testmethoden
Am im Forum: Rund um die Programmierung

Zitat von CSL

public void Create_ValidSessionGenerated()
{
    SessionCreator creator = new SessionCreator();
    ISession session = creator.Create("myName", "myPassword");

    Assert.IsNotNull(session);
    Assert.IsTrue(session.IsLoggedIn);
    Assert.IsFalse(session.IsReadOnly);
    Assert.AreEqual(session.UserName, "My User Name");
}

Hi,

genau solche Konstrukte hatte ich auch schon sehr häufig. Mittlerweile bin ich mir jedoch sicher, dass es sinnvoll ist dafür mehrere Tests zu schreiben.
Das Argument "wenn das erste Assert fehlschlägt, dann werden die restlichen nicht mehr evaluiert" finde ich hier als Begründung unsinnig. Dann behebe ich halt den Fehler und schaue, ob danach die folgenden Asserts korrekt sind.

Weshalb ich genau von solchen Mehrfachtests Abstand nehme ist also ein anderer Grund: Was passiert, wenn ich die Session z.B. dahingehend erweitere, dass ein aktueller Timestamp gesetzt wird? Weiterhin ist eine Session nur gültig, wenn dieser Timestamp nicht älter als x Minuten ist.
Das kann ich dann auch per Unit-Test überprüfen. Nur wer garantiert mir, dass der Implementierende nicht einen neuen Test schreibt und dabei nicht vergisst den obigen mit Erwartung "ValidSessionGenerated" auch anzupassen? Unter Umständen habe ich dann einen Test, der grün ist, aber nur weil die Validität gar nicht mehr vollständig überprüft wird.

Ich vermeide mittlerweile Testnamen, die Worte wie "valid" enthalten. Was heute noch "valid" ist, ist es morgen vielleicht schon nicht mehr. Deshalb lieber nur noch harte Fakten testen... und das geht meistens nur mit einem Assert pro Test.

Grüsse,

N1ls

Thema: Deserialisierung duch User canceln
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo Stefan O.,

Zitat von Stefan O.
man sollte Exceptions nicht verwenden um den Programmfluss zu steuern.

Immer dieses dogmatische Denken. Ich steuere IMMER den Programmfluss, sobald ich eine Exception werfe. Darf ich jetzt nach Deiner Aussage folgend niemals eine Exception werfen?

Den aktiven Abbruch eines lang laufenden Prozesses durch den Benutzer halte ich für einen absolut legitimen Grund, eine Exception zu benutzen. Das ist aus meiner Sicht auch kein Hack.

MfG,

N1ls

Thema: Ableiten oder Komposition?
Am im Forum: Rund um die Programmierung

Zitat von Golo Roden
Begründung Nr. 1: Die Basisklasse erfüllt keine "eigene" Funktionalität, es geht nur um das Auslagern von gemeinsamem Code. Insofern ist eine Basisklasse - zumal abstract - hierfür IMHO in diesem Fall die richtige Wahl.

Begründung Nr. 2: Helper-Klassen sind mir immer suspekt. Helper-Klassen haben oft so eine Aura der Art "Ich wusste nicht, wo ich das Zeug sonst hinpacken sollte".

Hallo Golo,

das sind genau die Punkte, die aus meiner Sicht gegen eine Vererbung sprechen.

1. Code auslagern und später wieder dranflanschen ist nicht Aufgabe der Vererbung. FCoI - Favour Composition over Inheritance. D.h. es reicht nicht aus, dass kein Grund gegen Vererbung spricht, es muss ein guter Grund dafür sprechen.
Gerade, wenn es keine Mehrfachvererbung gibt verbaue ich mir durch soetwas diese Möglichkeit an den wirklich sinnvollen Stellen.

2. Ja, Helper hört sich immer sehr unelegant an. Nennen wir das Kind einfach "Context" und es trifft genau das, was es ist. "In Deinem Context, benutze bitte diesen Logger"... Und das will ich gar nicht vererben. Das gebe ich per DI rein. Von daher Dein Hinweis schon ganz richtig ;-)

Grüsse,

N1ls

Thema: Tatsächlicher Nutzen von Unit-Tests [und TDD]
Am im Forum: Rund um die Programmierung

Hallo zusammen,

interessante Diskussion, ich klink mich mal ein ;-)

Zitat von CSL
In einem Tab blätter man auch weiter, nur halt indem man auf die Tab Header klickt, nach deiner Logik müsste das umschalten der Tabs auch ins ViewModel.
Zitat von CSL
Natürlich gehört das in die View, denn sie Zeigt ja die geblätterten Controls an.
Es war tatsächlich zu beginn so das die View alle Controls zuerst in Tabs anzeigte, das hatten wir dann zwecks Übersicht geändert sodass man durch die Liste iteriert.

Öhm... kurz und bündig: Nein! Kann ich überhaupt nicht unterschreiben.

Golo hat dazu schon seine Meinung geschrieben, die ich absolut nicht teile, obwohl wir zum selben Ergebnis kommen ;-)
Zitat von Golo Roden
Nein, ein TabControl gehört in die View. Weil es ein Control ist, das etwas anzeigt.

Das ist meiner Meinung nach zu platt (formuliert). Wir müssen uns als Entwickler meiner Meinung nach viel mehr mit der Semantik von Controls auseinandersetzen.

Ein TabControl gehört halt nicht (nur) in die View, weil es von Control abgeleitet ist. Es gehört auch nicht in die View, weil es etwas anzeigt. Der Punkt ist, dass es nichts, aber auch gar nichts anderes tut. Natürlich kann ich durch geschicktes Anordnen der Tabs die Reihenfolge, wie sie durchgeklickt werden sollten nahelegen. Ebenso kann ich visualisieren, wie eng zwei Tabs miteinander verwandt sind, indem ich sie nahe zusammen stelle. Mehr jedoch nicht.

Was ist aber mit den "Vor"- und "Zurück"- respektive "Fertig"-Buttons? Sowas baut man nicht "zwecks Übersicht" ein. Ganz im Gegenteil. Dadurch gebe ich dem Benutzer die Hand und leite ihn. Entweder durch einen bestimmten Prozess oder aber durch ein bestimmtes Schema, welches dem besseren Verständnis dient. Unter Umständen kann ich sogar den "Weiter"-Button nicht klicken, weil eine gewissen Voraussetzung auf der aktuellen Seite nicht erfüllt ist.
Das sind alles Geschichten, die meiner Meinung nach ganz klar nicht mehr der View gehören, das ist Business-Logik.

TabControl und "Vor, Zurück"-Dialog sind also semantisch gar nicht äquivalent. Um es noch einmal zu unterstreichen, erlaube ich mir es nochmals zu zitieren:
Zitat von CSL
nach deiner Logik müsste das umschalten der Tabs auch ins ViewModel.


Nein, weil hinter dem Umschalten der Tabs aufgrund der semantischen Bedeutung eines TabControls keine (Business-)Logik liegen darf.

Nur meine Meinung...

Grüsse,

N1ls

Thema: Softwareverteilung: Kennt der Anbieter den Nutzer?
Am im Forum: Rund um die Programmierung

Hallo zusammen,

Zitat von Andavos
da sprichst du einen guten Punkt an, dies ist mit dem Push Prinzip in der Tat leichter zu kontrollieren.

Genau das ist aus meiner Sicht ein ganz wesentliches Merkmal, was meines Erachtens nach absolut fuer ein Pull-Prinzip spricht. Kontrolle zu haben bedeutet immer: Verantwortung übernehmen.

Nehmen wir mal das Paracetamol-Szenario und ein abgerauchtes Rechenzentrum, in dem der Update Server steht... ähm... stand. Bei einem reinen Push-Prinzip hätte demnach der Software-Anbieter die volle Verantwortung und somit die Pflicht, alle Kunden über die Änderungen wenigstens zu informieren und darauf hinzuweisen, dass diese momentan noch nicht in der Software berücksichtigt werden.
Beim Pull-Prinzip hingegen würde die Software melden "Ich konnte mich nicht zum Update-Server verbinden, Du arbeitest mit einer Version von <<DATUM>>." Dann liegt die Verantwortung jedoch ganz klar beim Kunden.

Was in diesem Fall die Gesetzgebung angeht: Ich glaube nicht, dass ein Apotheker mit der Begründung "unsere Software hat nicht gemeckert, als ich die Grosspackung Paracetamol ohne Rezept rausgegeben habe" durchkommt. Software kann in solchen Bereichen helfen, Fehler zu vermeiden, aber definitiv nicht Verantwortung abnehmen/übernehmen.

Fazit: Durch einen Pull-Mechanismus gibt der Software-Anbieter einen grossen Teil der Verantwortung an den Kunden weiter. Die Verantwortung regelmässig und zeitnah Updates zur Verfügung zu stellen bleibt, das macht dann die Produktqualität aus.

Soweit meine Gedanken dazu,
im Übrigen wünsche ich allen hier ein frohes neues Jahr ;-)

N1ls

Thema: [gelöst] wozu finally-Block
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo Bit2_Gosu,

der Thread ist zwar schon als geloest gekennzeichnet, mir fehlt hier aber auf jeden Fall noch der Begriff "Ressourcenschutzblock" ;-)

Dann wird sich wahrscheinlich auch folgende Frage klaeren:

Zitat von Bit2_Gosu
Mal schaun, ob ich finally jemals brauchen werde

Mal ein ganz einfaches Beispiel, wie so ein Ressourcenschutzblock mit try und finally aussehen kann:


    FileStream fs = new FileStream("file.txt", FileAccess.Read);
    try
    {
         // do something with filestream
    }
    finally
    {
        fs.Close();
    }

Es gibt jetzt 3 Faelle, an denen deutlich wird, was dieses Konstrukt genau macht.

1. Beim Oeffnen des Filestreams tritt eine Exception auf. Dann wird der Try-Block gar nicht erst durchlaufen und folglich auch der Finally-Block.
2. Der Filestream kann korrekt geoeffnet werden, im Try-Block tritt keine Exception auf. Der Filestream wird dann auf jeden Fall im Finally-Block korrekt geschlossen.
3. Der Filestream kann korrekt geoeffnet werden, im Try-Block tritt allerdings eine Exception auf. Trotzdem wird der Filestream korrekt geschlossen.

Fall 1 ist der dabei der eigentlich interessante. Daran wird deutlich, wieso der Filestream unbedingt ausserhalb des try-finally geoeffnet werden muss. Ich habe schon oefter folgendes gesehen:


    try
    {
         FileStream fs = new FileStream("file.txt", FileAccess.Read);
         // do something with filestream
    }
    finally
    {
        fs.Close();
    }

Was passiert, wenn beim oeffnen des Filestreams eine Exception ausgeloest wird? Richtig: Direkt danach wird im Finally-Block versucht einen nicht geoeffneten Filestream zu schliessen. Dann kommt es zu einer neuen Exception.

Deshalb sollte man immer Ressourcen allokieren(in diesem Falle ein File-Handle fuer den Filestream), in einem Try-Block (der nur ausgefuehrt wird, wenn die Allokierung erfolgreich war) mit diesen Ressourcen arbeiten und diese dann im Finally-Block wieder freigeben.

Kurze Anmerkung: Da FileStream das Interface IDisposable implementiert, koennte man obiges Beispiel natuerlich auch mit der Using-Direktive einfacher benutzen, aber es ging ja hier um den grundsaetzlichen Sinn von try-finally ;-)

Ich hoffe durch dieses Beispiel wird die Notwendigkteit von try-finally noch ein wenig klarer. Grundsaetzlich gilt, dass die Vorraussetzungen fuer den Finally-Blocks bereits vor dem Try-Block geschaffen werden muss.

Gruesse,

N1ls

Thema: FSM in C# entwickeln
Am im Forum: Buchempfehlungen

Hallo Golo,

Tutorial kenne ich leider keines(auch nicht in anderen Programmiersprachen), aber im Grunde genommen ist es nicht besonders schwer, eine FSM zu implementieren.

Geht es Dir eher darum, wie man diese ueberhaupt implementieren kann oder um die effizienteste Moeglichkeit? Letzteres wird man in einem Tutorial sowieso nicht finden koennen, da dies immer problemspezifisch ist und es oft einen Trade-off zwischen Speicherbedarf und Geschwindigkeit gibt.

Ich hab ehrlich gesagt auch keine Ahnung, wie die Workflow Foundation intern arbeitet. Mit dem Workflow-Editor kann man ja weitaus mehr modellieren als mit FSMs. *oehm* Falsch bzw. nicht ganz korrekt. Man kann eigentlich jeden beliebigen Workflow auch als FSM modellieren, nur muss man dann zusaetzliche "Hilfszustaende" einbauen. Z.B. um nebenlaeufige Prozesse abbilden zu koennen.

Meine Erfahrung: FSM implementieren ist relativ einfach. Ohne Kenntnis, was Du machen willst, ist aber schwer zu beurteilen, ob das wirklich das ist, was Du willst. Frage ist ja auch noch, ob ein Automat nach Mealy oder Moore? Die Antwort haengt immer vom Problem ab.

Vielleicht komme ich die Tage mal dazu, ein kleines Beispiel zu implementieren. Kann ich aber aus Zeitnot momentan nicht versprechen...

Gruesse,

N1ls

Thema: Singularity Quelltext veröffentlicht
Am im Forum: Szenenews

Hi Big Al,

Zitat von Big Al
Der Quellcode steht unter deiner Lizenz, die eigentlich nur kommerzielle Nutzung verbietet und ansonsten fast alles erlaubt.

Das stimmt so nicht. Auch bei nicht kommerzieller Nutzung wird immer wieder darauf hingewiesen, dass diese ausschliesslich bei akademischen Projekten etc. erlaubt ist. Von "ansonsten fast alles erlaubt" kann hier also nicht die Rede sein, eher das Gegenteil: Sehr stark begrenzt.

Finde das aber trotzdem 'ne coole Sache.

Gruesse,

N1ls

Thema: SQL: Eine Einführung
Am im Forum: Datentechnologien

Hallo,

Zitat von FZelle
@N1ls:
Jede Tabelle, die von Anfängern benutzt wird sollte einen PK besitzen,
denn sonst können Einsteiger den Commandbuilder und/oder die Assistenten
nicht benutzen.

Das faellt dann aber eher unter die Rubrik "best practice (for beginners)". Dagegen habe ich ja gar nichts. Aber gerade in einem Einsteiger-Tutorial zu vermitteln, dass jede Tabelle zwingend einen PK haben MUSS, ist einfach falsch.

Gruesse,

N1ls

Thema: SQL: Eine Einführung
Am im Forum: Datentechnologien

Zitat von v.wochnik
Sagt mir bitte eure Meinung hierzu.

Hm. Ich bin da skeptisch. Das Tutorial richtet sich an Einsteiger. Die Basics vermitteln mir, dass

1. eine Datenbank ueber mehrere Tabellen verfuegt. Ist das so? Ich habe heute noch 'ne DB neu angelegt. Ich lasse mal die Schema-Tabellen weg. Also aus Benutzersicht und speziell aus Sicht eines Einsteigers sind da erst einmal 0 Tabellen gewesen. Und mehrere bedeutet fuer mich immer mindestens 2.

2. jede Tabelle einen Primaerschluessel besitzt. Waere mir absolut neu. Stimmt auch Gott seid Dank nicht ;-)

3. jede Datenbank Zugangsdaten benoetigt. Stimmt auch nicht. Wer zwingt mich dazu, einer DB Zugangsdaten zu verpassen?

Das sind meiner Meinung nach ganz gravierende Fehlinformationen. Ohne ueberhaupt zu wissen, wie man eine SQL-Datenbank einrichtet, wird der Einsteiger komplett in die Irre gefuehrt.

Bitte nicht falsch verstehen. Das Projekt ein solches Tutorial zu erstellen finde ich sehr gut. Mir gefaellt auch, wie Du das darstellst. Aber dann bitte nur mit hart recherchierten Fakten und mit einem Referenzsystem zum Ausprobieren. Kein Einsteiger wird mit einem solchen Tutorial klar kommen, wenn er schon kein Testsystem hat.

Hoffe, das hilft Dir ein wenig Dein Tutorial zu erweitern / verbessern.

Gruesse,

N1ls

Thema: Designfrage: Daten ohne Userrechte anzeigen?
Am im Forum: Rund um die Programmierung

Hallo Hannes,

Zitat von HannesB
Wäre es eurer Meinung nach eine sinvolle Kompromisslösung, z.B. die Pakete 4+5, auf die der User kein Recht hat "disabled" anzuzeigen?
Dadurch verlagere ich diese Logik jedoch in den Client (!) - die Serveranwendung müsste alle 5 Packete zurückgeben mit der Anmerkung, dass der User eigentlich nur auf Paket 1-3 Leserecht hat.

Die Logik, was die Absicherungen der Zugangsberechtigungen angeht bleibt (bei korrekter Implementierung) weiterhin beim Server.

Etwas konkretisiert sieht es doch ungefaehr so aus, dass die 5 Pakete mehr oder weniger aus 5 Paaren von Paketnamen und Paketdaten uebertragen werden. Also:

Paketname 1, Paketdaten 1
Paketname 2, Paketdaten 2
Paketname 3, Paketdaten 3
Paketname 4, Paketdaten 4
Paketname 5, Paketdaten 5

Jetzt die Uebertragung fuer den Fall, dass nur Leseberechtigungen fuer Pakete 1-3 vorhanden sind:

Paketname 1, Paketdaten 1
Paketname 2, Paketdaten 2
Paketname 3, Paketdaten 3
Paketname 4, NULL
Paketname 5, NULL

Daten, auf die der Benutzer keine Leserechte hat, werden vom Server nicht geliefert. Wenn der Client "bemerkt", dass fuer Paket 4 und 5 keine Daten uebertragen wurden, kann er daraus schliessen, dass die Berechtigungen des Benutzers nicht ausreichen. Das kann dann durch eine entsprechende Darstellung kenntlich gemacht werden (z.B. auch disabled) oder sogar ausgeblendet werden. Kann natuerlich auch noch durch ein zusaetzliches Flag realisiert werden, aber sicherheitstechnisch liegt die volle Kompetenz "wer darf was lesen?" beim Server.

Gruesse,

N1ls

Thema: FTP - Can't open data connection
Am im Forum: Netzwerktechnologien

Zitat von DragothiX
Unterstützt jeder FTP Server im passive-mode auch den active-mode, sodass ich einfach den Code so ändern kann, dass ich darüber zugreifen könnte oder muss ich dafür auch auf dem Server etwas umstellen?

Es geht ja anscheinend um Deinen Win-Server... also einfach ausprobieren ;-)

Thema: FTP - Can't open data connection
Am im Forum: Netzwerktechnologien

Zitat von DragothiX
Ich verbinde über den Port 21 und habe jetzt bereits mehrmals gelesen, dass zum Datentransfer Port 20 benutzt wird.

Das ist so ungefaehr die halbe Wahrheit. Bei FTP-Uebertragung werden beim Dateitransfer immer auch irgendwelche unprivileged Ports (> 1023) benutzt. Im Active-Mode stellt der Client diesen Port zur Verfuegung, was problematisch ist, wenn man hinter einem NAT-Router o.Ae. sitzt, im Passive-Mode wird dieser Port vom Server bereitgestellt (dementsprechend evtl. Firewall-Probleme).
Zitat
Der Server ist ein Windows Server 2003, auf dem sowohl Port 20 als auch Port 21 in der Firewall durchgeschaltet wird.

Wie erwaehnt, reicht das nicht, wenn versucht wird ueber den Passive-Mode zuzugreifen.
Zitat
Der Datentransfer mittels "normaler" FTP-Clients wie dem WindowsCommander oder WSFTP_LE funktioniert übrigens prächtig.

In der Regel versuchen die FTP-Clients auf verschiedene Weise zuzugreifen. Also, wenn Passive nicht funzt, dann wird Active versucht. Probier mal mit dem Internet Explorer auf den ftp zu kommen ("ftp://servername/verzeichnis" bzw. mit Authentifizierung "ftp://username:[email protected]/verzeichnis"). Das wird, denke ich mal, auch nicht funktionieren.
Zitat
Kann ich die Datei eigentlich auf einem anderen Wege als per FTP übertragen?

Klar. Z.B. WebDAV, Http-Upload, eigener TCP-Server auf dem Zielrechner, Remoting, einfache Windows-Freigabe. Die Moeglichkeiten sind eigentlich unbegrenzt. Einzige Voraussetzung: Ausreichende Berechtigungen auf dem Server ;-)

Hope that help, Gruesse,

N1ls

Thema: BinarySearch zwei string Arrays vergleichen
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo tire0011,

Zitat von tire0011
Problematik: ich habe zwei Arrays und möchte den Unterschied einem dritten Array zuweisen. Die Suche soll auf Leistung ausgerichtet sein, also sehr schnell gehen. Unten ist ein Beispiel-Code, in Zukunft könnten die Arrays umfangreicher sein, daher die Frage.

...
folgenden Beispiel Code:


static void Main(string[] args)
        {
            string[] Array1 = {"cycle", "rectangle", "line"};
            string[] Array2 = {"cycle", "rectangle", "line", "connector","stencil"};
           .
           .
           .
        }

Im Array3 ist, soll folgendes Ergebnis enthalten sein:
Array3[0] = "connector";
Array3[1] = "stencil";

Nochmal eine Nachfrage zum Problem: Meiner Meinung nach deckt sich Deine Problembeschreibung nicht mit dem von Dir geposteten Algorithmus. Woran kann man sich eher orientieren, an der Beschreibung oder dem Algorithmus?

Ich fasse mal Deinen Algorithmus in Worte: Array3 beinhaltet alle Elemente, die in Array2 zusaetzlich zu den Elementen in Array1 vorhanden sind.

Ist es das, was Du willst? Koennen z.B. folgende Faelle auftreten und was erwartest Du als Ergebnis in Array3?

Fall1:

string[] Array1 = {"cycle", "rectangle", "line", "connector","stencil"};
string[] Array2 = {"cycle", "rectangle", "line"};

Fall2:

string[] Array1 = {"xyz", "rectangle", "line", "connector","stencil"};
string[] Array2 = {"cycle", "rectangle", "line"};

Falls diese Faelle auch beruecksichtigt werdem sollen, dann erhoeht sich die Komplexitaet des Problems weiter. Die Loesung Dictionary/Hash waere sicherlich immer noch die Loesung, aber der Algorithmus muesste auch entsprechend angepasst werden.

Gruesse,

N1ls

Thema: BinarySearch zwei string Arrays vergleichen
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo Herbivore,

Zitat von herbivore
an dem Punkt stimmen wir ja über ein. Das habe ich ja schon oben geschrieben. Der Sortieraufwand entfällt bei Dictionary..

Oops. Sorry, Deinen Satz ueber das Sortieren hab ich ueberlesen und daher angenommen, dass Du es als "Aepfel mit Birnen"-Vergleich gesehen haettest.

Okay, hab's jetzt nochmal genau gelesen und es ist immer noch kein A&B-Vergleich. Einfach aus dem Grunde, dass ich nichts verglichen habe, sondern nur festgestellt habe, dass die Add-Operation lediglich den Aufwand O(1) hat. Das ist ja nicht selbstverstaendlich ;-)

Um jetzt aber nicht zu sehr an solchen Feinheiten neben dem Topic herzuschwameln

@zommi

5000 Durchlaeufe, um Messungenauigkeiten zu umgehen ist ein gutes Mittel. Viel interessanter waere aber mal, wie Du die Testdaten generiert hast. Weil interessant waere hier ja mal eine Gegenueberstellung der verschiedenen Ansaetze mit unterschiedlichen Testdatengroessen.

Wobei... hm... GUIDs?

Gruesse,

N1ls

Thema: BinarySearch zwei string Arrays vergleichen
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo herbivore,

Zitat von herbivore
Allerdings vergleichst du hier Äpfel mit Birnen. Das Hinzufügen (Add) eines Elements zu einer Liste kostet mit O(1) genau soviel wie das Hinzufügen zu einem Dictionary. Und wenn man eine ganze Dictionary kopiert, kostet das genauso O(n) wie das Kopieren eine Liste O(n) kostet. Hier liegen die Performance-Vorteile also nicht.

Vergiss dabei aber nicht, dass die Binaersuche nur mit einer sortierten Liste funktioniert. D.h. ich muss also das Array sortieren, sonst funktioniert der Algorithmus nicht (hat tire0011 auch korrekterweise in dem Code-Beispiel gemacht).

Von daher profitiere ich an dieser Stelle zusaetzlich vom Hash... ich spare mir das Sortieren, muss aber im Gegenzug einmal das Array in das Dictionary kopieren. Und dabei ist der Aufwand O(n) in der Regel guenstiger als jeder Sortieralgorithmus.

Gruesse,

N1ls