Jan 182017
 

Vor einiger Zeit stand ich vor dem Problem, dass ich in einer Assembly feststellen musste, wo ich denn jetzt eigentlich laufe, um davon dann meine Weiterverarbeitung innerhalb der Assembly abhängig zu machen. Das hört sich erst einmal komisch an, lag aber daran, dass ich hier eine komplett autarke Komponente nicht wieder von anderen Assemblies abhängig machen wollte. In diesem Fall gab es dann auch gleich mehrere Möglichkeiten:

  • innerhalb einer von mir geschriebenen Anwendung
  • innerhalb einer von einem mir unbekannten Entwickler geschriebenen Anwendung (z.B. Konsole oder Desktop)
  • innerhalb des Unittest Runners

Die von mir geschriebene Anwendung besitzt natürlich einen Strong Name und zwar genau wie meine unabhängige Assembly. D.h. also, dass ich einfach den Public Key des aufrufenden Prozesses (eigene Anwendung, unbekannte Anwendung, Unittest Runner) mit dem Public Key meiner Assembly vergleichen kann und damit ganz einfach dieses Problem lösen konnte. Über Reflection kommt man auch relativ einfach an die entsprechenden Informationen, die man dafür braucht, heran.
Die folgende Methode ist dabei entstanden und liefert true zurück, wenn der Code der Assembly innerhalb einer von mir signierten Anwendung (Prozess) läuft. In allen anderen Fällen wird ein false zurückgeliefert.

Ist eigentlich ganz einfach und funktioniert bei mir ohne Probleme. Den entsprechenden Unittest erspare ich euch hier an dieser Stelle aber einfach einmal. Solltet ihr dennoch daran Interesse haben, dann einfach einen Kommentar hinterlassen und ich trage ihn noch schnell nach :-).

Apr 042016
 

Das Singleton Entwurfsmuster wird in einer Softwarearchitektur verwendet, um sicherzustellen, dass eine Objektinstanz nur einmal erzeugt wird und diese zumeist auch noch global verfügbar ist. Ich verwende es in meinen Entwürfen genau dann, wenn ich dem Anwender die Möglichkeit geben möchte, möglichst einfach auf zentrale Funktionen der zugrundeliegenden Architektur zuzugreifen und diese auch nur einmal vorhanden sein sollen. Es gibt einige Nachteile die man sich dadurch einfängt und eines der Hauptprobleme liegt sicherlich beim Testen. Wie testet man bspw. die Erzeugung des Singletons richtig? Schliesslich wird das Singleton bereits kreiert wenn ich es zum ersten Mal aufrufe und da meine Tests unabhängig voneinander laufen sollen, würden meine nachfolgenden Tests vom bereits kreierten Singleton beeinflusst werden, was ich auf jeden Fall vermeiden möchte.

In unseren Anwendungen verwenden wir immer separate Unittest Assemblies, um die eigentlichen Assemblies mit der Funktionalität zu testen. Die Sichtbarkeit wird über das „InternalsVisibleTo“ Attribut (siehe meinen vorherigen Artikel) für das zu testende Assembly so geändert, dass mit dem „internal“ Modifizierer versehenen Klassen, Methoden, Properties, etc. für das Testassembly sichtbar sind. Im Singleton kann jetzt eine Methode oder ein „set“ eingebaut werden, die das Singleton wieder sauber entfernt.

In der folgenden Klasse habe ich eine „Close()“ Methode implementiert und das „Instance“ Property erweitert. Welche der beiden Wege ihr bevorzugt hängt davon ab, ob weitere Aufräumarbeiten beim Schließen des Singletons notwendig sind (in diesem Fall würde ich eine Methode implementieren) oder ob ein einfaches Setzen des „Instance“ Properties auf „null“ bereits ausreichend ist.

Abschließend sei noch zu erwähnen, dass ich es versuche die Modifikation von Quellcode für anschließende Unittests zu vermeiden, da ich der Meinung bin, dass man damit bereits in die Programmlogik eingreift und Fehler verursachen könnte. Die Modifikation des Singletons halte ich deshalb für eine technische Krücke, die man an dieser Stelle leider nicht vermeiden kann. Wie macht ihr das in eurem Code? Ähnlich oder habt ihr eine elegantere Möglichkeit?

Jan 232015
 

Beim Schreiben von Unittests bin ich mal wieder darüber gestolpert, dass jemand speziell für die Unittests Getter und Setter angelegt hat, da er auf die privaten Variablen der Klasse nicht zugreifen konnte. Im Prinzip hat er damit für seinen Unittest die internen Variablen dann über den Zugriffsmodifizierer public dann doch wieder sichtbar gemacht, wenn auch nur indirekt. Das ist so natürlich nicht gewollt, denn sonst hätte man gleich den Zugriff auf die internen Variablen erlauben können. Vielleicht noch kurz zur Erklärung: unsere Unittests sind immer in eigenständige Assemblies ausgelagert, sodass wir von Außen auf die zu testenden Klassen zugreifen müssen. Das macht auch Sinn, da die Unittests in dem Kompilat nicht enthalten sein sollen. Wie kann man das Problem also lösen?

Das .NET Framework bietet dafür das Attribut InternalsVisibleTo aus dem Namespace System.Runtime.CompilerServices an. Um nun die internal Methoden, Variablen und Properties freizugeben, wird das Attribut in die AssemblyInfo.cs des zu testenden Projekts eingefügt.

Danach kann man mit dem im InternalsVisibleTo-Attribut angegeben Assembly seine Unittests auf den Klassen durchführen ohne alles Zugriffsmodifizierer auf public zu setzen.

Solltet ihr eure Assemblies signieren, muss das einzufügende Attribut um den Public Key des zugreifenden Assemblies erweitert werden. Zusätzlich muss außerdem das zugreifende Assembly signiert werden. Der Eintrag in der AssemblyInfo.cs sieht dann so aus:

Das ist natürlich nur eine Herangehensweise, aber – wie ich finde – eine doch recht elegante. Wie macht ihr das in euren Unittests? Habt ihr eine ähnliche Vorgehensweise oder schreibt ihr einfach gar keine ;-)?

Dez 082014
 

Bei der Entwicklung von Unittests für mein privates Windows Store und Windows Phone Projekt bin ich bei der Konvertierung der alten Unittests für die Portable Class Library (PCL), die in dem Projekt verwendet wird, darüber gestolpert, dass auf einmal das „ExpectedException“ Attribut nicht mehr gefunden wird. Dieses Attribut verwendete man in den Unittests, um Tests zu kennzeichnen, die eine Exception werfen müssen. So richtig sauber war das allerdings irgendwie noch nie, da man eigentlich die einzelnen Bedingungen mittels „Assert“ geprüft hat. Es ist also nur konsequent, dass das Attribut mittlerweile entfernt wurde und durch eine entsprechende Methode in der Assert-Klasse ersetzt wurde. Folgendes kleines Beispiel zeigt die Verwendung der Methode „ThrowsException“:

Simpel, oder? Hat mich allerdings trotzdem etwas Zeit gekostet, da ich mit dieser Änderung erst mal nicht gerechnet habe.

Durch die weitere Nutzung der Seite stimmst du der Verwendung von Cookies zu. Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen