Das Notes Forum

Lotus Notes / Domino Sonstiges => Java und .NET mit Notes/Domino => Thema gestartet von: flaite am 15.10.07 - 18:21:20



Titel: Mock-Framework für JUnit Tests
Beitrag von: flaite am 15.10.07 - 18:21:20
Hi,

ich arbeite an der entgültigen Strategie zum Junit-Testing von Notes-Agents.

Was ich will:
1. Notes soll für Junit Tests von Notes Agenten nicht gestartet werden.
2. Junit Tests sollen relativ einfach geschrieben werden können.

Denke nun, dass Stubbing und nicht die verschiedenen Mock-Frameworks (wie JMock1 ) einfacher und flexibler ist.
Was verstehe ich unter Stubs?
Einfach Klassen, die die Notes Interfaces implementieren. Schliesslich läuft der gesamte öffentliche Zugriff auf die Notes Api ja über Interfaces.
Stubs für Notes Java Klassen lassen sich mit Eclipse sehr einfach erstellen:
Beispiel: Klasse DocumentStub erzeugen, die einfach das Interface lotus.domino.Document implementiert. Für alle Methoden des Interfaces lotus.domino.Document werden von Eclipse schon Methodenrümpfe erstellt. Die kann ich dann möglichst wiederverwendbar erweitern.
Kann man z.B. für getItemValue, getItemValueString und getItemValueInteger so implementieren:
Code:

public Vector getItemValue(String name) throws NotesException {
Vector ret = new Vector();
Object val = itemValueMap.get(name);
if (val != null) {
ret.add(val);
}
return ret;


}

public int getItemValueInteger(String name) throws NotesException {
Vector vec = getItemValue(name);
if (vec.size() == 0) return 0;
Object firstEntry = vec.get(0);
if (firstEntry instanceof Number) {
if ((firstEntry instanceof Double)|| (firstEntry instanceof Float)) {
return ((int) Math.round(((Double)firstEntry).doubleValue()));
} else {
return (int) ((Long) firstEntry).intValue();
}
} else {
return 0;
}
}

public String getItemValueString(String name) throws NotesException {
Vector vec = getItemValue(name);
if (vec.size() == 0) return null;
Object firstEntry = vec.get(0);
if (firstEntry instanceof String) {
return (String) firstEntry;
} else {
return null;
}
}
Das liesse sich dann für alle Projekte  benutzen.
Die Stub Objekte besitzen eine private HashMap itemValueMap, in der die Feldwerte drinstehen:
Code:
private Map itemValueMap = new HashMap();

public void addItemValue(String name, Object value) {
itemValueMap.put(name, value);
}
Diese itemValueMap kann über addItemValue von aussen gefüllt  werden.
Solche bei Bedarf immer mehr zu verfeinernden allgemein-verwendbare Notes Stub Objekte für Junit-Testing tu ich in ein eigenes Eclipse Projekte, dass ich dann problemlos in spezielle Projekte einbinden kann.

Oder ist das Quatsch? Ich halte die Idee zur Zeit für so großartig, dass ich mich wundere, warum kein anderer darauf gekommen ist.

Gruß Axel


Titel: Re: Stubs und kein Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 15.10.07 - 19:20:22
Hm... Nach meinem Verständnis von Mocks und Stubs, könnte man deine Klasse auch als Mock, heißt übersetzt Attrappe, bezeichnen. Auf Basis der Übersetzung passt das, was du baust sehr gut dazu, so ich finde. Ein Stub (dt. Stummel) ist ja auch nicht viel anders, nur hätte ich gedacht, dass da zT konstante Werte zurückgegeben werden. An sich finde ich die Idee aber gut, vor allen Dingen kann man damit leichter Unit-Tests durchführen und teilweise auch testgetrieben entwickeln. Wenn ich diese Klasse sehe, fällt mir noch ein, dass man ja den Mock eigentlich auch noch testen muss, was du aber bestimmt auch tust.

Dabei kommt mir aber noch eine weitere Idee: Kann man das nicht auch für andere Notes-Objekte machen und das als "Test-Framework" zusammenstellen?


Titel: Re: Stubs und kein Mock-Framework für JUnit Tests
Beitrag von: flaite am 16.10.07 - 10:06:35
Du hast Recht.
Ich benutze auf jeden Fall nicht Mock-Tools wie EasyMock und JMock1 (JMock2 ist nur für Java5). Das verleitete mich zu falschen Begriffen. Das ist mehr eine Art eigenes Notes-Mock-Objekte Package. 
Es ist ein bischen wie Spring-mock.jar (das dort für Integration-Testing verwendet wird).
http://static.springframework.org/spring/docs/1.2.x/reference/testing.html#integration-testing
Notes-Mock wäre mehr für Unit-Testing. Sobald eine einzelne Klasse Abhängigkeiten zu lotus.domino.* Klassen hat, benötigt man Mocks (oder Stubs), um das zu testen, ohne mit Notes selbst zu kommunizieren.
Notes mocken funktioniert ziemlich gut, weil die ganze apis aus Interfaces besteht.
Wobei ...Für bestimmte Notes-Methoden wirds vermutlich ziemlich schwierig dort geeignete Mock-Klassen selbst zu schreiben (z.B. RichText). Die Brot-und-Butter-Funktionalität (wichtigsten Funktionen von Database, View, DocumentCollection, Document, Item) lassen sich aber vermutlich mit vertretbaren Aufwand mocken.
Die Notes-Designer Funktionalität, java-Source Files über den Edit-Projekt Button direkt von dem entsprechenden Verzeichnis im Eclipse Projekt zu importieren funktioniert für Java-SkriptBibliotheken (nicht zu verwechseln mit JavaScript-ScriptBibliotheken) und Java-Agenten sehr gut.
Mit funktionierenden Notes-Mock-Packet lassen sich Notes-Agenten (und Notes Java-ScriptBibliotheken) sehr schnell testgetrieben oder/und unit-testgestützt entwickeln.
Ich könnte den Import von der Platte-wo-Eclipse-das-hinlegt in den Notes-Agenten oder die Notes Java-ScriptBibliothek noch per Ant-Script automatisieren. Oder Domiclipse verwenden, das aber nicht weiterentwickelt wird.
Ein falscher Weg ist imho, dass mehrere  Entwickler mit Domiclipse den GLEICHEN Notes-Java-Agenten oder NOTES-Java-Scriptbiothek entwickeln zu lassen. Dann eher schon erst testgestützt/testgetrieben entwickeln, den Code in einem Versionierungssystem halten und zu einem geeigneten Zeitpunkt dann die neuen Source Files dann auf den eigentlichen Testserver spielen. Die Prozesse könnte man natürlich noch mit sowas wie CruiseControl automatisieren.
Ich schau mal wie weit ich komme.
Einen Markt für Notes-Agenten gibts schon. Wenn z.B. Dateien als zips in eine Mail-In-DB kommen und dann weiterverarbeitet werden sollen, Zugriff über HTTP auf andere Server, aus einem gif Informationen herausholen, wie breit und hoch die ist, etc.

Gruß Axel


Titel: Re: Stubs und kein Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 17.10.07 - 07:49:43
Was die technische Umsetzung anbelangt in Bezug auf "Koppelung" von externen Java-IDEs wie Eclipse mit dem Designer habe ich mir noch nicht so wirklich Gedanken gemacht, da es bisher für mich nicht aktuell war. Wird es wohl die nächste Zeit auch nicht werden, da in meinem neuen Unternehmen überhaupt kein Notes eingesetzt wird.

Genau den Gedanken für die Basis-Funktionen hatte ich auch, eine View oder auch eine Collection ist wohl mit vertretbarem Aufwand zu simulieren in einigen Bereichen. Man sollte aber auch hier eben durch Tests versuchen sicherzustellen, dass die Attrappen auch tun, was sie sollen.

Ich denke mal, dass testgetriebene Entwicklung eine gute Sache ist, da man durch die Unit-Tests eine Menge Sicherheit in Bezug auf Änderungen bekommt, sofern die existierenden Testfälle gut sind.


Titel: Re: Stubs und kein Mock-Framework für JUnit Tests
Beitrag von: flaite am 17.10.07 - 10:13:34
Übrigens benutzen auch unsere Sharepoint-Entwickler Unit-Testing.
Was die technische Umsetzung anbelangt in Bezug auf "Koppelung" von externen Java-IDEs wie Eclipse mit dem Designer habe ich mir noch nicht so wirklich Gedanken gemacht,
Wenn man den richtigen Prozess hat, kann man Notes Agenten vollständig in Eclipse entwickeln.
Völlig problemlos. Man braucht nicht mal Domiclipse. Alles andere sind Mythen. Hat mich selbst ein wenig überrascht.
Im Agenten Fenster im Designer kann man über Edit Process / Local File System / Base Directory auf src Ordner des Eclipse Projekts auf der Platte stellen und Import. Importiert neue, ersetzt bestehende. Und zwar alles unterhalb des src Ordners.
Man entwickelt den Agenten und die Java-ScriptBibliotheken in Eclipse (mit der Notes Java VM als eingetragene VM für das Projekt). Die dort erzeugten Java Klassen kann man problemlos vom Designer aus importieren. Das ist Deployment.
Vereinfacht gesprochen hat man für deployment-Prozesse immer ein Source-Repository auf der einen Seite und eine Zielplattform auf der anderen Seite. In ant-getriebenen Prozessen, pusht man den Inhalt des source-repository in die Zielplattform. In Notes pullt man aus der Zielplattform die Inhalte des source repository. Dieser Pull-Prozess ist nur ein wenig umständlicher. Ich könnte vermutlich eine funktionierende ant-Erweiterung schreiben, die pusht. Schliesslich besitzt Domiclipse den entsprechenden Code. So wichtig ist das aber gar nicht, da pull nur wenig zeitaufwendiger ist. 

Für jede Java-ScriptBibliothek hab ich ein eigenes Projekt in Eclipse. Jeder Agent auch. Die Abhängigkeiten zwischen Agenten - Java-Scriptbibliotheken und Java-ScriptBibliotheken lassen sich in Eclipse problemlos nachbilden (JavaBuild Path, Project - Tab). Das sind dann natürlich recht viele Projekte. Die organisiere ich aber unter einem Working-Set in Eclipse.
Ich bemühe mich um separation of concern (kommt man über testgestützte Entwicklung quasi von alleine drauf). D.h. Notes wird sowieso nur in sehr wenig Klassen angesprochen. Der Rest ist sowieso problemlos unit-testbar.
Java Agenten nimmt man für Spezialaufgaben, für die es in Notes allenfalls plattformabhängige Möglichkeiten mit C-Apis gibt. Z.B. entzippen von Bildern, ausmessen von height, width, grösse in Bytes der Bilder und importieren der Bilder in Notes RichText Objekte. Oder Kommunikation mit externen Webservices. In solchen Agenten ist der Anteil Klassen, die mit Notes kommunizieren, ohnehin relativ gering. Die Kern-Funktionalität ist von Notes unabhängig und somit Unit- und Integrations-testbar. Ein solches Notes-Mock Paket wäre quasi nur noch die letzte Meile, dass auch Methoden, die in Notes Agenten Notes-Klassen ansprechen, unit-testbar werden.





Titel: Re: Stubs und kein Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 17.10.07 - 17:03:59
Das klingt ja doch recht praktikabel... Habe mich zu "Notes-Zeiten" da nie intensiv mit auseinandergesetzt, da Java nicht benötigt wurde und es ansonsten auch niemand beherrscht bei meinem vorherigen AG.


Titel: Re: Stubs und kein Mock-Framework für JUnit Tests
Beitrag von: flaite am 17.10.07 - 18:08:06
Wär eine Sache, die ich auf unseren Unternehmensblog stellen könnte:
Agile Java Entwicklungstechniken mit Lotus Domino 7.
Wenn hier nicht so viel zu tun ist.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 07.11.07 - 08:32:27
Mein entsprechender Vorschlag auf idea jam hat sehr wenig Interesse generiert (http://ideajam.net/IdeaJam/P/ij.nsf/0/0A44CD430184CF7D8625738A003B1180?OpenDocument). Naja. Zumindest ist einer der beiden promoter Vorgesetzter. Hab am WE letztens ein bischen weitergeschrieben und hoffe am nächsten WE einen ersten Prototypen zu haben. Bislang siehts sehr machbar aus und es bringt eine Menge für einen deutlich effizienteren Prozess des Schreibens von Java Agenten für Lotus Domino.
Die unterstützen Klassen sind: Database, Document, Item, View, ViewColumn, DocumentCollection, Session und AgentContext.
Unmittelbare Kandidaten sind: Agent, DateTime, DateRange und Stream.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 07.11.07 - 08:47:28
Das klingt sehr vielversprechend, was du da schreibst. Ich beschäftige mich auch gerade mit Tests...


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 28.12.07 - 15:10:53
Jetzt hab ich endlich Zeit.
Die Mock-Klassen Item und Document sind schon relativ komplett. Geb mir echt Mühe, es richtig zu machen. Gibt eine Menge Details (das nicht sehr Java kompatible Typ System, Response-Beziehungen, etc).
Werd wohl auch die Kandidaten (Agent, DateTime, DateRange und Stream).
Hoffe am 6.1. relativ weit zu sein und kann dann meinen Arbeitgeber fragen, ob wir das openSourcen können (wird wohl klappen).
Mein entsprechender Vorschlag auf idea jam brachte sehr gemischte Reaktionen.
http://tinyurl.com/2bqjle
Its because the naysayers just don't get it.  ;D
Es bringt nämlich unmittelbare und sehr offensichtliche Vorteile für den Prozess zur Entwicklung von Java-Agenten, Java-Skriptbibliotheken und Code für Notes-Zugriff.
Und ist auch für verschiedene Zielgruppen an Entwicklern gerichtet
Gruppe A:  Java Programmierer ohne viel Notes Erfahrung
Gruppe B:  Notes Entwickler ohne viel Java oder Unit-Testing Erfahrung
Gruppe C:  Angeber, die behaupten sowieso alles zu können

Wenn Gruppe B keine Lust auf Junit-Tests hat, kann man das Mock-Framework sogar benutzen, ohne überhaupt selbst Junit-Tests zu schreiben. Es ist einfach ein Nachbau der Notes Api und der Notes-Datenbank-Struktur, die völlig ohne Notes und sehr gut in Eclipse, Netbeans, Intelij-IDEA, etc. lebt.
Der Code kann direkt in einer IDE geschrieben und getestet werden und wird dann erst am Ende in die reale Notes-Datenbank exportiert. 
Ansonsten ist es heute zwar sehr einfach Notes-Java Code in Eclipse zu schreiben und das dann auch in Notes importieren. Der Bruch findet nur immer dann statt, wenn man testen will. Das importieren selbst sind zwar wenige aber immerhin Handgriffe. Ausserdem kann man nur remote debuggen und das macht überhaupt keinen Spaß.
Mit dem Framework kann man lokal debuggen und nahtlos code-schreiben / testen.
Für Unit-Test aficionados kommt natürlich die Möglichkeit von Test Driven Development und das Vorhandensein eines Regressions-Test-Sicherheits-Netz hinzu.

Inzwischen gibts übrigens ein Projekt auf openNTF, das auf Unit-Testing für LotusScript abzielt (http://tinyurl.com/ypdm3t). Werd das auf jeden Fall ausprobieren. Kann mir nicht vorstellen, dass das Sinn macht. Das können aber Vorurteile sein.

Gruß Axel


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 01.01.08 - 18:34:52
Sieht gut aus.
Falls jemand Interesse hat, schick ich bis zum 15.1. eine einfach zu benutzende Ausstattung mit Beschreibung der Einrichtung einer Umgebung in Eclipse.
(axel punkt janssen at gmail punkt com
Das ist keine Bug-Show. Ist dann wirklich stabil.
Meine eigene Implementierung unterstützt die grundlegenden Merkmale einer Notes Datenbank, die für die Aufgabe benötigt werden.
Ansichten mit Selektionsformeln (zur Zeit: Itemname-Formeln, dh. sowas wie Select form = "maske1" und @all) und Sortierung.
DocumentCollection
Spalten. 
Dokumente, Profil-Dokumente.
Items (kein RichText, z.Zt. keine Datumsfelder).
AgentBase, Session und AgentContext müssen noch. Die sind aber auch nicht so groß. 

Liefer das mit Beispielen aus und will nicht endlos erklären.
Kann wirklich auch für Java noobs interessant sein. 


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 03.01.08 - 21:25:18
Hier mein erster Agent auf meinem eigenen Notes:

Man beachte, dass die ganzen verwendeten Notes Klassen quasi "Nachbauten" sind. Für dieses Testsystem, braucht kein Notes auf dem Rechner vorhanden sein. Ok. Ausnahme ist noch die Klasse lotus.domino.NotesException. Ist ja auch ne beta  ;D

Ging eigentlich ziemlich gut, wobei mein eigenes Notes nicht komplett ist.
Aber zumindest ich brauch für die meisten Java Agenten eben diese Klassen.
Weitere Klassen können natürlich noch hinzugefügt werden. RichText wird vermutlich nicht so einfach, aber wer weiss.
Ziemlich gut gelungen ist schon die Sortierung von Ansichten.  8)

Code:
package de.spintegration.mock.examples;

import java.util.Vector;

import java.util.Iterator;

import lotus.domino.NotesException;

import de.spintegration.notes.mock.AgentBase;
import de.spintegration.notes.mock.AgentInfo;
import de.spintegration.notes.mock.Database;
import de.spintegration.notes.mock.Document;
import de.spintegration.notes.mock.DocumentCollection;
import de.spintegration.notes.mock.Item;
import de.spintegration.notes.mock.MockFactory;
import de.spintegration.notes.mock.View;
import de.spintegration.notes.mock.ViewColumn;

/**
 * @author ajanssen
 *
 */
public class SimpleAgent extends AgentBase {


/* (non-Javadoc)
* @see de.spintegration.notes.mock.AgentBase#NotesMain()
*/
public void NotesMain() {
try {
System.out.println ("********************************");
System.out.println ("SESSION.GETNOTESVERSION :-). ");
System.out.println ("********************************");

System.out.println(session.getNotesVersion());
Database dbCur = agentContext.getCurrentDatabase();
View vw1 = dbCur.getView("ansicht1");


System.out.println ("********************************");
System.out.println ("ANSICHT");
System.out.println ("********************************");

System.out.println(vw1.prettyPrint());

Document docAfro = vw1.getDocumentByKey("Afrika");
Vector itemAfro = docAfro.getItems();
Iterator itItemAfro = itemAfro.iterator();

System.out.println ("********************************");
System.out.println ("FELDWERTE DES PER DOKUMENT-by-Key(Afrika) gefundenen Dokuments");
System.out.println ("********************************");

while (itItemAfro.hasNext()) {
String fieldName = itItemAfro.next().toString();
Item item = docAfro.getFirstItem(fieldName);
System.out.println(item.getName() + "-->" + item.getValues());
}

System.out.println ("********************************");
System.out.println ("KONGO-Dokument einfügen");
System.out.println ("UND BEACHTET WIE SICH DAS EINSORTIERT, KONTINENT UND LAND SIND SORTIERTE SPALTEN,s. main Methode oben");
System.out.println ("********************************");


Document docNewAfro = dbCur.createDocument();
docNewAfro.replaceItemValue("form", "maske5");
docNewAfro.replaceItemValue("kontinent", "Afrika");
docNewAfro.replaceItemValue("land", "Kongo");
docNewAfro.replaceItemValue("staedte", "Kinshasa");
docNewAfro.save();

System.out.println(vw1.prettyPrint());


System.out.println ("********************************");
System.out.println ("Dokument Collection-> GIBT JA JETZT 2 DOKUMENTE MIT KEY AFRIKA");
System.out.println ("********************************");

DocumentCollection colAfro = vw1.getAllDocumentsByKey("Afrika");
docAfro = colAfro.getFirstDocument();

while (docAfro != null) {
itemAfro = docAfro.getItems();
itItemAfro = itemAfro.iterator();

System.out.println ("********************************");
System.out.println ("Dokument IN Collection");
System.out.println ("********************************");

while (itItemAfro.hasNext()) {
String fieldName = itItemAfro.next().toString();
Item item = docAfro.getFirstItem(fieldName);
System.out.println(item.getName() + "-->" + item.getValues());
}

docAfro = colAfro.getNextDocument();
}




} catch (NotesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}

public static void main (String[] args) throws NotesException {
/*
* ERSTMAL MUSS DIE DATENBANK DEFINIERT WERDEN
* IST ZUGEGEBEN EIN WENIG MÜHSELIG.
* WERD ABER EINE MÖGLICHKEIT DER DEFINITION DER DATENBANK MIT XML ANBIETEN.
*/
MockFactory fac = MockFactory.getInstance();
Database parentDatabase = fac.getDatabase("test", "test.nsf");

// view definieren -> SORTIERUNG BEACHTEN.
View vw1 = fac.addView(parentDatabase, "ansicht1", "@all");
fac.addViewColumn(vw1, "form", "form");
fac.addViewColumn(vw1, "kontinent", "kontinent", ViewColumn.SORT_ASCENDING);
fac.addViewColumn(vw1, "land", "land", ViewColumn.SORT_ASCENDING);
fac.addViewColumn(vw1, "städte", "staedte");


// DOKUMENTE DIE VOR LAUF DES AGENTEN DA SIND. 
Document doc1 = fac.addDocumentWithForm(parentDatabase, "maske1");
doc1.replaceItemValue("kontinent", "Europa");
doc1.replaceItemValue("land", "Deutschland");
Vector vecStädteDoc1 = new Vector();
vecStädteDoc1.add("Köln");
vecStädteDoc1.add("Hannover");
vecStädteDoc1.add("Frankfurt");
doc1.replaceItemValue("staedte", vecStädteDoc1);
doc1.save();

Document doc2 = fac.addDocumentWithForm(parentDatabase, "maske2");
doc2.replaceItemValue("kontinent", "Europa");
doc2.replaceItemValue("land", "Groß Britannien");
Vector vecStädteDoc2 = new Vector();
vecStädteDoc2.add("London");
vecStädteDoc2.add("Glasgow");
vecStädteDoc2.add("Manchester");
doc2.replaceItemValue("staedte", vecStädteDoc2);
doc2.save();

Document doc3 = fac.addDocumentWithForm(parentDatabase, "maske3");
doc3.replaceItemValue("kontinent", "Amerika");
doc3.replaceItemValue("land", "Argentinien");
Vector vecStädteDoc3 = new Vector();
vecStädteDoc3.add("Buenos Aires");
vecStädteDoc3.add("Cordoba");
vecStädteDoc3.add("Mendoza");
doc3.replaceItemValue("staedte", vecStädteDoc3);
doc3.save();

Document doc4 = fac.addDocumentWithForm(parentDatabase, "maske4");
doc4.replaceItemValue("kontinent", "Asien");
doc4.replaceItemValue("land", "Indien");
Vector vecStädteDoc4 = new Vector();
vecStädteDoc4.add("Mumbai");
vecStädteDoc4.add("Kalkutta");
vecStädteDoc4.add("Bangalore");
doc4.replaceItemValue("staedte", vecStädteDoc4);
doc4.save();

Document doc5 = fac.addDocumentWithForm(parentDatabase, "maske5");
doc5.replaceItemValue("kontinent", "Afrika");
doc5.replaceItemValue("land", "Maroko");
Vector vecStädteDoc5 = new Vector();
vecStädteDoc5.add("Marakesch");
vecStädteDoc5.add("Fes");
vecStädteDoc5.add("Rabat");
doc5.replaceItemValue("staedte", vecStädteDoc5);
doc5.save();

// set AGENTIFO
AgentInfo agInfo = new AgentInfo(fac);
agInfo.setCurrentDatabase(parentDatabase);


// AGENT STARTEN
SimpleAgent sa = new SimpleAgent();
sa.startup(agInfo);
}

}

und hier die Ausgabe:

Code:
********************************
SESSION.GETNOTESVERSION :-).
********************************
Happy Sandbox Notes, Release 0.4 Copper Edition|21st Century.
********************************
ANSICHT
********************************
Datenbank=test(test.nsf)
Ansicht=ansicht1, Selektionsformel=@all

form  |kontinent|land           |städte                      |
______|_________|_______________|____________________________|
maske5|Afrika   |Maroko         |Marakesch,Fes,Rabat         |
______|_________|_______________|____________________________|
maske3|Amerika  |Argentinien    |Buenos Aires,Cordoba,Mendoza|
______|_________|_______________|____________________________|
maske4|Asien    |Indien         |Mumbai,Kalkutta,Bangalore   |
______|_________|_______________|____________________________|
maske1|Europa   |Deutschland    |Köln,Hannover,Frankfurt     |
______|_________|_______________|____________________________|
maske2|Europa   |Groß Britannien|London,Glasgow,Manchester   |
______|_________|_______________|____________________________|

********************************
FELDWERTE DES PER DOKUMENT-by-Key(Afrika) gefundenen Dokuments
********************************
staedte-->[Marakesch, Fes, Rabat]
form-->[maske5]
land-->[Maroko]
kontinent-->[Afrika]
********************************
KONGO-Dokument einfügen
UND BEACHTET WIE SICH DAS EINSORTIERT, KONTINENT UND LAND SIND SORTIERTE SPALTEN,s. main Methode oben
********************************
Datenbank=test(test.nsf)
Ansicht=ansicht1, Selektionsformel=@all

form  |kontinent|land           |städte                      |
______|_________|_______________|____________________________|
maske5|Afrika   |Kongo          |Kinshasa                    |
______|_________|_______________|____________________________|
maske5|Afrika   |Maroko         |Marakesch,Fes,Rabat         |
______|_________|_______________|____________________________|
maske3|Amerika  |Argentinien    |Buenos Aires,Cordoba,Mendoza|
______|_________|_______________|____________________________|
maske4|Asien    |Indien         |Mumbai,Kalkutta,Bangalore   |
______|_________|_______________|____________________________|
maske1|Europa   |Deutschland    |Köln,Hannover,Frankfurt     |
______|_________|_______________|____________________________|
maske2|Europa   |Groß Britannien|London,Glasgow,Manchester   |
______|_________|_______________|____________________________|

********************************
Dokument Collection-> GIBT JA JETZT 2 DOKUMENTE MIT KEY AFRIKA
********************************
********************************
Dokument IN Collection
********************************
staedte-->[Kinshasa]
form-->[maske5]
land-->[Kongo]
kontinent-->[Afrika]
********************************
Dokument IN Collection
********************************
staedte-->[Marakesch, Fes, Rabat]
form-->[maske5]
land-->[Maroko]
kontinent-->[Afrika]



Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 03.01.08 - 21:47:05
Da hast du aber bisher ganze Arbeit geleistet, Axel! Sieht echt nicht schlecht aus...


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 03.01.08 - 22:09:36
Danke. Vor allem mehr Arbeit als ich dachte.
Ich feil noch ein paar Ecken ab, bau vielleicht noch ein paar Features ein (so dafür Zeit ist) und geb das am 15. raus.
Ich kanns wirklich selbst gebrauchen, wobei ich natürlich auch nicht weiss, ob ich nächstes Jahr viele Notes Agenten schreiben werde.
Hat aber auch wirklich Spaß gemacht das zu schreiben.
UniqueIDs und DocIDs gibts auch (ist auch nicht so schwierig, weils nicht verteilt ist).
Nächstes Feature wären Leserfelder wirklich unterstützen. Vielleicht das Notes-Datumszeugs. Gehen tut das alles.
Vielleicht interessieren sich Kerr Rainey oder Ben Poole dafür.
Mein AgentContext hat vor und nach Aufruf von NotesAgent einen Interceptor. Damit kann man difs vor und nach dem Agentlauf für Unit-Tests schreiben. Ist aber noch nicht getestet.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 07.01.08 - 16:46:17
Vielleicht verwende ich irgendwann couchDB als Persistenz-Speicher, hihi. (http://damienkatz.net/2008/01/new_gig.html)
Zur Zeit ist das ja eine reine in-memory Datenbank, was für unit-Tests auch völlig richtig ist.

Gruß Axel 


Titel: Implementierte Methoden soweit
Beitrag von: flaite am 14.01.08 - 10:38:56
... in der attachten html-Datei.
hellgrün -> implementiert.
rotbraun -> nicht implementiert.

Manche der nicht implementierten Methoden sind recht obskur oder betreffen das UI (z.B. setShowTwistie() in der Klasse ViewColumn).
Die Datei ist generiert mit einem zusäztlichen Hilfs-Projekt, einfach mit Java-Reflection.

Neue Features können noch recht schnell hinzugefügt werden
- folders
- "Mail"-Methoden wie document.send() -> mit interceptoren, die die vom Agenten "versendeten" Mails in eine Art Queue schreiben, so dass sie etwa durch Unit-Tests überprüfbar sind.

Auf ein interessantes Problem bin ich gestossen:
Unterschiedlicher State von Dokumenten. Wenn ich den state eines vorher gespeicherten Dokuments ändere. (Etwa durch doc.replaceItemValue(fieldName, value), sind diese Werte ja nicht im Notes-Dokument abgebildet, wenn ich es über das Backend neu lade (etwa per database.getDocumentByUNID) bevor ich die State-Änderungen per doc.save() ins Backend schreibe. Da weiss ich noch nicht richtig, wie ich das abbilde. Sollte jemand das Problem verstehen und eine Idee haben, immer her damit. Vielleicht bietet es sich an, couchDB - an dem ja der wieder-IBM Mitarbeiter Damien Katz weiterarbeitet - als eine Art Persistenzmanager zu verwenden. Muß das aber noch prüfen. Ist jetzt aber sowieso nicht top-Prio.

Gruß Axel


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 14.01.08 - 14:36:07
Hm... Ich habe gerade dein Posting gelesen. Nach wie vor finde ich das ein gutes Projekt und bin doch sehr überrascht, wie stark man Notes doch "mocken" kann.

Zu deiner Frage:
Kann man dein Problem nicht evtl über eine Art Caching-Mechanismus und Proxies lösen? Also die Dokumente liegen in einem zentralen Cache, aus dem sie bei den verschiedenen Lade-Methoden als Proxy ausgeliefert werden. Beim Speichern wird dann der Proxy an den Cache gegeben, wo er versucht die neuen Daten ins Original zurückzuschreiben. Nur so als Idee. An der Stelle hast du dann auch die Chance Replizierkonflikte zu erzeugen, wenn nämlich zwei zur gleichen Zeit geholte Dokumente zu unterschiedlichen Zeiten zurückschreiben wollen. Was hälst du von dem Vorschlag?

EDIT: Noch eine weitere Idee, zur Ansiedlung des Dokumenten-Cache: Der sollte vielleicht je Notesdatenbank verfügbar sein.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 14.01.08 - 15:26:56
Mit Proxy hat das glaub ich nichts zu tun.

Durch die Persistenz in Notes, können unterschiedliche Versionen von Document-Objekten mit der gleichen DocUnid existieren.
Code:
Document docNew = db.createDocument();
docNew.replaceItemValue("form", "form1");
docNew.save();
Document docFromPersistedMem = db.getDocumentByUNID(docNew.UniversalID);
docNew.replaceItemValue("land", "Germany");

docNew und docFromPerstistedMem haben die gleiche UniversalID.
Das Objekt docNew hat am Ende des scripts ein Feld "land".
Das Objekt docFromPersistedMem hat dieses Feld dagegen nicht.
Erst durch ein docNew.save() würden beide Versionen wieder synchronisiert.

Das ist durch mein MockFramework zur Zeit schwer abzubilden, da es gar keinen persistenten Speicher hat. Die Dokumente sind rein in-Memory, dh. sie liegen in Database in (mehreren) Maps.

Zur Abbildung wäre es vermutlich am einfachsten, wenn ich eine Persistenzschicht einziehen würde. Eine Persistenzschicht zu simmulieren, dürfte auch machbar sein.
Allerdings bewege ich mich hier schon in Corner-Cases, die nicht Bestandteil der 1. Version sind.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 14.01.08 - 15:33:14
Stimmt, richtige Proxies sind das nicht so wirklich. Es sind ja keine Stellvertreter in dem Sinne.

Aber vom Prinzip würde ich nur Kopien ausliefern und die dann auf die Originale zurückschreiben.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 15.01.08 - 09:16:43
Das stimmt vermutlich mit den Kopien. Nur muss ich die eben als tiefe Kopien ausliefern.
Ein Document enthält Item Objekte. Da können nicht einfach die Referenzen kopiert werden, sondern es müssen eben echte Kopien erstellt werden. In den Items sind wiederum String-, Number- und Datums-Objekte. Da können immer dann Referenzen kopiert werden, wenn die Klasse inmutable ist.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 15.01.08 - 09:33:17
Das klingt so schonmal recht sinnvoll so. Ich hoffe, dass dir meine Hinweise oder auch Ideen weiterhelfen...


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 15.01.08 - 18:48:20
Ja klar.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 16.01.08 - 11:49:13
Werd die Infos in unseren Unternehmensblog stellen und den Code in dem Subversion System von Google Code. Das mit dem Blog eher Ende Januar, da der welcher wirklich gut Englisch kann zur Lotussphere fährt. Upload nach Subversion vermutlich nächsten Montag.

Heute nutzt das ein Junior Entwickler, der kein Java kann, für eine Aufgabe. Werd das mal beobachten. Schreib selbst noch ein anspruchsvolleres Beispiel mit Einbindung von JFreeChart (das erzeugt Diagramme wie Balken, Kuchen, etc.).   

Fertig:
die wichtigsten Methoden der Klassen Session, AgentContext, AgentBase, Database, View, ViewColumn, DocumentCollection, Item, Name.


Die nächsten 4 Wochen:
- Deklaration der Struktur der Umgebung (Session, Database, Ansichten, Ordner, vorhandene (Profil-) Dokumente mit XML (bisher macht man das über eine einfache Factory-Klasse).
- Funktionalität von Leser- und Autorenfeldern.
- Unterstützung von Unit-Tests für Code, der von aussen auf Notes zugreift und von LS2J.
- aus Backend-Methoden wie view.getFirstDocument(), etc., database.getDocumentByUNID() wird eine Kopie des Objekts zurückgeliefert (bisher nur Objekt selbst). So können auch Speicherkonflikte simuliert werden.
- Überprüfung von recycle-Aufrufen.
- Datetime-Klasse
. Attachments in Dokumenten.

Weitere Pläne:
- RichText
- DXL
- Agent
- Mime


Noch weitere Pläne:
- API komplett
- Unterstützung einer selbstgeschriebenen @formula Engine in Java mit dem ANTLR Parser-Generator Framework.
 


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 16.01.08 - 11:56:24
Respekt Axel... Das ist ja schon richtig umfangreich, was du da hast... Die Sache mit der @Formula-Engine würde mich persönlich aber auch mal interessieren. Gib mir mal einen Wink, wenn du damit anfangen willst, evtl habe ich dann Zeit um da was mit dran zu machen.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 16.01.08 - 14:59:11
FTSearch will ich auch irgendwann machen. Mit Lucene. Damit können auch die meisten Attachments durchsucht werden.  ;D
Der Code ist aber zu weiten Strecken echt einfach. Das war mehr tippen als programmieren. Die Views (Selektion, Spalten und Sortierung) und die Interceptoren ist wirklich das einzige, was ein bischen komplexer ist.
 
Das Projekt ist auch internationalisiert und ich werd Übersetzungstabellen für Deutsch, broken englisch und gringo-Spanisch hinterlegen. Für die Korrektur der Übersetzungen und die Anlage neuer Übersetzungstabellen sind keine Programmierkenntnisse notwendig. Aber das ist eh Standard in vielen Java-Projekten.

Die Formelsprache-Engine in Java erfordert erst mal ein bischen konzeptionelle Arbeit. Zumindest hab ich ein ANTLR Buch. Der Domiclipse Entwickler hat versucht, ANTLR auf Lotus-Script anzuwenden. Die Reaktion auf meinen entsprechenden Vorschlag auf IDEA Jam war nicht so überragend. Ist aber klar, weil eben ziemlich tief programmatisch.
http://ideajam.net/IdeaJam/P/ij.nsf/0/6021FB054E497FFA862573CA0041C196?OpenDocument


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: MadMetzger am 16.01.08 - 15:58:29
Naja, erstmal einen Schritt nach dem anderen. Aber die Parsergeschichte interessiert mich halt, von daher hatte ich mein Interesse geäußert. Der zunächst aufwändigste Part wird dann wohl die Grammatik für den Parser sein, denke ich mal. Aber danach muss man ja auch die @Funktionen implementieren, damit man auch interpretieren kann. Ich finde das sehr interessant, obwohl ich beruflich nichts mehr mit Notes zu tun habe. Das daraus gewonnene Wissen kann man ja garantiert an anderer Stelle weiterverwenden.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 29.01.08 - 10:21:43
Das zugegeben zur Zeit etwas schleppend weiterentwickelte Mockframework kann jetzt xml-Konfigurationsdateien zur Deklarierung der "Umgebung" einlesen.

Unter Umgebung verstehe ich so Sachen wie Datenbanken, Ansichten, Ordner, Dokumente.
Java-Agenten, LS2J Zeugs oder externe Javaprogramme, die mit dem Framework entwickelt und testbar gemacht werden sollen erwarten ja so etwas wie eine Umgebung.

Hier eine Beispiel-Konfigurationsdatei:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<declaration>
<database title="music" path="music.nsf">
<view name="byYear" formula="form={music}">
<column title="year" formula="year" sort_policy="ASCENDING"
type="int" response="false" />
<column title="type" formula="type" />
<column title="artist" formula="artist" />
<column title="title" formula="title" />
</view>
<view name="all" formula="@all">
<column title="form" formula="form" sort_policy="ASCENDING" />
</view>
<folder name="wantHear" formula="form={music}">
<column title="artist" formula="artist"
sort_policy="ASCENDING" />
<column title="title" formula="title"
sort_policy="Ascending" />
<column title="year" formula="year" />
<column title="type" formula="type" />
</folder>

<profile form="profile">
<item name="aProfField">
wert
</item>
</profile>

<document form="music">
<item name="year" type="NUMBERS">1835</item>
<item name="artist">Robert Schumann</item>
<item name="type" sep=",">Clasic, Romantic</item>
<item name="title">Von fremden Ländern und Menschen</item>
</document>

<document form="music">
<item name="year" type="NUMBERS">1977</item>
<item name="artist">Joy Division</item>
<item name="type" sep=",">Pop</item>
<item name="title">Control</item>
</document>





</database>

</declaration>

Damit werden dann in der Umgebung die im xml deklarierten Datenbank(en), die Ansichten, die Profildokumente, die Ordner und die Dokumente angelegt.

Hier ist Testcode, der die obige xml einliest:
Code:

MockFactory fac = MockFactory.getInstanceXmlDecl("mockfactory.xml");
Session s = fac.getSession();
Database db = s.getDatabase("", "music.nsf");
View vw = db.getView("byYear");
;
System.out.println(vw.prettyPrint());


Hier ist das Ergebnis vom System.out des Testcodes:
Code:
Datenbank=music(music.nsf)
Ansicht=byYear, Selektionsformel=form={music}

year|type            |artist         |title                           |
____|________________|_______________|________________________________|
1835|Clasic, Romantic|Robert Schumann|Von fremden Ländern und Menschen|
____|________________|_______________|________________________________|
1977|Pop             |Joy Division   |Control                         |
____|________________|_______________|________________________________|


Sobald sich das xml stabilisiert, werd ich dafür ein xml-Schema schreiben. So kann leichter validiert werden, ob die Eingaben des Benutzers im xml ok sind. 
Xml ist natürlich ein ziemlich geschwätziges Format, aber man kann da prima mit copy und paste arbeiten und es ist eben ziemlich selbsterklärend.
Ich denke auch darüber nach DXL einlesen zu können, das kommt aber später.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: m3 am 06.02.08 - 14:36:29
Falls noch nicht bekannt:

Zitat
Using easymock for disconnected Domino Java testing

For his testing he would rather not connect to the Domino server all the time, but instead mock up objects to make sure that his other code works correctly. Enter EasyMock, which is a JAR file which you can include in any project that basically pretends to be whatever object you want it to be.

http://www.11tmr.com/11tmr.nsf/d6plinks/MWHE-7BKDJC


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 11.02.08 - 10:35:15
Das ist natürlich auch eine Lösung.
Je mehr Logik auf Domino selbst zugreift, desto löchriger und anstrengender wird dieser Ansatz mit JMock.
Werd noch diese Woche hochladen.
Bin noch ziemlich an kämpfen mit einer Ajax Anwendung, die budgetonisch aus dem Ruder gelaufen ist und einem Java-Kurs, den ich hier intern gebe.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: StephanKoo am 21.03.14 - 10:40:36
Moin,

kann man das Ergebnis nutzen? Der Thread hörte irgendwie so plötzlich auf.

Danke
   Stephan Koops


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: klaussal am 21.03.14 - 10:53:59
Das ist 6 Jahre her..... :o


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: StephanKoo am 21.03.14 - 10:58:19
ja, ich weiß, aber vielleicht ist das Ergebnis ja trotzdem nutzbar.


Titel: Re: Mock-Framework für JUnit Tests
Beitrag von: flaite am 26.03.14 - 15:01:07
Hab den code nicht mehr. Habs für ein Projekt genutzt. War aber dafür overkill. Danach hab ich afaik kein einziges Notes Projekt mehr gemacht.
Ich glaub, dass man sowas heute nicht mehr braucht. Hast Du mal versucht NotesJava Klassen mit mockito zu mocken?