\chapter{Implementatie} \section{Inleiding} De bedoeling van deze thesis is het implementeren van conditionele testen. Het schrijven van de code hiervoor bracht enkele problemen met zich mee. Deze zijn uitgelegd in de volgende sectie. \section{Problemen} \label{problemen} Het implementeren van condities is niet zo gemakkelijk als het lijkt. Je hebt namelijk twee soorten. De eerste soort zijn de condities die worden opgevangen door een event. Wanneer dit event dan getriggered wordt, kan in de code de conditie worden nagekeken. De tweede soort zijn condities waarvoor geen event wordt uitgestuurd. Als er bijvoorbeeld enkel getest wordt of een property een bepaalde waarde heeft, dan moet er een manier worden bedacht om dit op een of andere manier op te vangen. We weten niet exact wanneer een bepaalde waarde van een property verandert. Het probleem met de huidige implementatie bestaat erin dat er een algemene eventhandler wordt gekoppeld aan een widget per conditie. Zodra het event is getriggered wordt de actie, behorende bij de conditie, uitgevoerd. Bij condities is het echter toegelaten dat verschillende condities ge\"interesseerd zijn in hetzelfde event, maar komende van een verschillend widget. Een conditie kan bijvoorbeeld interesse hebben voor een klik op knop A en het checked zijn van checkbox B, terwijl een andere conditie interesse heeft voor een druk op knop A en het geselecteerde item van combobox C moet 1 zijn. Beide condities zijn ge\"interesseerd in een \texttt{`ButtonPressed'} event van knop A. Met andere woorden, het is niet meer mogelijk om het event (in dit geval \texttt{`ButtonPressed'}) te koppelen aan de actie van \'e\'en regel omdat er twee condities graag verwittigd zouden worden van dit event. De naam van het event dat juist is getriggerd en het part die het heeft getriggered moeten worden opgevangen en bijgehouden in een globale tabel voor een aantal seconden omdat meerdere condities hierin ge\"interesseerd kunnen zijn. Het is niet gemakkelijk omdat je slechts een eventhandler kan koppelen aan een bepaalde functie. Op deze manier weet de ontwikkelaar normaal aan welk widget hij deze functie koppelt, maar in de huidige implementatie wordt via reflectie alles gekoppeld aan \'e\'en functie per conditie. Hoe geven we de naam van het event dat juist getriggered is en de naam van het widget door? Een mogelijkheid bestaat erin de klasse `EventArgs' te gebruiken. Deze wordt namelijk als een parameter meegegeven aan de eventhandler. Er duikt echter een probleem op als we deze mogelijkheid volgen. De `EventArgs' klasse is een basis klasse waarvan andere kunnen afgeleid worden (voorbeelden hiervan zijn `MouseEventArgs' en `KeyPressEventArgs'). De afgeleide klasses bevatten extra informatie die voor het bijhorende event nuttig zijn. Zoals al gezegd is, worden events opgevangen in een algemene eventhandler. Deze eventhandler krijgt de basis klasse `EventArgs' mee zodat alle soorten kunnen opgevangen worden. Een oplossing voor dit probleem zal verder behandeld worden in sectie \ref{an_delegates}. \subsection{Kijken naar events} Spying is een methode om te kijken welke events er hebben plaatsgevonden. Het werkt met speciale `SpyEventArgs', een klasse afgeleid van `EventArgs'. Hierin kunnen eender welke parameters worden meegegeven die nodig zijn voor de ontwikkelaar. Er wordt dynamisch een functie aangemaakt die een bepaald event opvangt. Hierdoor kunnen we zelf een eigen gemaakte functie aanroepen wanneer er een bepaald event plaats vindt. Hoe we dynamisch code bijschrijven zal nu worden uitgelegd. \subsubsection{IlGenerator} IlGenerator\footnote{http://msdn2.microsoft.com/en-us/library/system.reflection.emit.ilgenerator.aspx} is een klasse van het .NET framework die ondersteund wordt vanaf versie 1.1. Het kan Microsoft Intermediate Language (MSIL) instructies genereren. Met deze klasse is het dus mogelijk om at runtime code bij te schrijven die niet op voorhand kan worden geschreven. Op deze manier kunnen events worden overschreven zodat deze een bepaalde functie aanroept bij wijziging en zelfs extra parameters mee geeft aan deze functie. Een code voorbeeld is te vinden in listing \ref{ilgenerator}. Als eerste wordt een methode met de naam \texttt{ReportEvent} opgehaald in de klasse \texttt{SWFEventLink}. Hierna wordt een methode van een eventhandler (nl \texttt{Invoke}) opgehaald. Om de functie ook daadwerkelijk aan te roepen worden alle parameters types opgeslagen in een tabel (\texttt{methodPars}). Vervolgens wordt de naam van de functie gegenereerd en wordt er een methode aangemaakt. Als laatste wordt de body ingevuld door rechtstreeks byte code te schrijven. Door middel van de functie \texttt{Emit} worden rechtstreeks instructies in de MSIL stream van instructies geschreven. OpCodes representeren velden van de MSIL instructies. Ldarg\_0 zal argument 0 op de stack laden. Wat deze code in feite voorstelt is het schrijven van de regel `\texttt{spy.ReportEvent("EventName", o, e)}' waarbij \texttt{o} de zender is en \texttt{e} de argumenten. Deze methode is heel effectief en heeft weinig tot zelfs geen overhead, er worden niet onnodig functies aangeroepen. Maar ILGenerator verbruikt veel resources voor at runtime code te genereren, waardoor de namespace waarin deze klasse zich bevind (\textit{System.Reflection.Emit}) niet ondersteund wordt op het .NET Compact Framework. Bovendien zal dit niet werken om wijzigingen van properties op te vangen omdat de spying klasse enkel een functie zal aanroepen als een event is uitgestuurd. Een uitbreiding kan echter gemaakt worden zodat deze ook de properties overschrijft. Telkens een property wordt gewijzigd kan dan een bepaalde functie worden aangeroepen. \lstset{basicstyle=\footnotesize, frameround=fttt, numbers=left, numberstyle=\tiny, language=[Sharp]C, breaklines=true} \begin{lstlisting}[float, frame=bt, caption=ILGenerator Voorbeeld, label=ilgenerator] MethodInfo miReportEvent = typeof(SWFEventLink).GetMethod("ReportEvent"); MethodInfo invoke = typeof(EventHandler).GetMethod("Invoke"); ParameterInfo[] pars = invoke.GetParameters(); int len = pars.Length; // Haal de parameter lijst op Type[] methodPars = new Type[len]; for (int i = 0; i < len; i++) { methodPars[i] = pars[i].ParameterType; } // Maak event naam bv 'Click' wordt 'OnClick' String methodName = "On" + eInfo.Name; // Maak een method MethodBuilder method = theClass.DefineMethod(methodName, MethodAttributes.Public, typeof(void), methodPars); // Schrijf de method body ILGenerator il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, fld); il.Emit(OpCodes.Ldstr, eInfo.Name); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Callvirt, miReportEvent); il.Emit(OpCodes.Ret); // Voeg de nieuw gemaakte event handler toe eInfo.AddEventHandler(targetObject, Delegate.CreateDelegate(eInfo.EventHandlerType, impl, "On" + eInfo.Name)); \end{lstlisting} \subsection{Event uitsturen} Nieuw in .NET 2.0 is de interface \texttt{INotifyPropertyChanged}. Met deze interface kan je gemakkelijk een event uitsturen wanneer een property wijzigt. Het doet eigenlijk min of meer hetzelfde als custom events schrijven. Dus het nadeel is onmiddellijk duidelijk, je moet zelf de functie \texttt{NotifyPropertyChanged(string property);} aanroepen. Dit is niet mogelijk aangezien we tijdens het schrijven van de code niets weten over de property waarin de ontwikkelaar van de UI ge\"interesseerd is. \subsection{Kijken of een property verandert} \begin{figure}[h] \center \includegraphics[scale=1.75]{images/polling.png} \caption{Polling} \label{polling} \end{figure} Een manier om te kijken of een waarde van een property is verandert, is om de x milliseconden te pollen. Dit wil zeggen dat er iedere x milliseconden een stuk code wordt opgeroepen. Het is dan de bedoeling om alle condities af te gaan. Voor iedere conditie moet dan gekeken worden of alles evalueert naar \textit{waar}. Het probleem met polling bestaat erin dat er nogal wat overhead geproduceert wordt, zeker als de user interface een moment idle is. Want dan wordt nog altijd gepold. Polling is dus niet geschikt om te werken op toestellen die zuinig moeten omspringen met hun resources, zoals een smartphone of een PDA. Er zou teveel van de batterij van deze toestellen gevraagd worden. Er moet een manier gevonden worden om polling te vermijden. Met andere woorden, er moet iets gevonden worden waardoor je een property van een widget kan volgen. Wanneer er iets verandert aan die property, zou dit een event moeten uitsturen. Dit event kan dan worden opgevangen, en de nodige condities kunnen getest worden. \section{Condition manager} We zitten nog altijd met vraag: Hoe vangen we de wijziging van een property van een widget op? De idee is dat bij iedere verandering van staat van een widget, alle condities opnieuw moeten bekeken worden om te zien of er door deze wijziging een conditie evalueert. Mijn implementatie zorgt er dan ook voor dat alle condities worden ondergebracht in \'e\'en object. In dit object worden ook alle events afgehandeld. Waarom er wordt gewerkt met een manager wordt uitgelegd in sectie \ref{de_manager}. Hierin bevindt zich ook de globale tabel waarover gesproken is in sectie \ref{problemen}. In de rest van deze paragraaf zal eerst besproken worden hoe de events nu worden opgevangen om daarna verder te gaan met het opvangen van de property wijzigen. \subsection{Anonieme delegates} \label{an_delegates} Om te weten welk event juist getriggered is, wordt er gebruik gemaakt van anonieme delegates. Wat een delegate precies is, werd al uitgelegd in sectie \ref{huidige_impl}. Een anonieme delegate is een functie zonder een naam. Hierdoor wordt de code gereduceerd doordat er geen aparte functie moet worden aangemaakt. In listing \ref{wrapper} is een code voorbeeld te zien van de wrapper die gebruikt wordt. In dit voorbeeld is te zien dat er anonieme delegate wordt aangemaakt. Er wordt namelijk een functie teruggegeven. Als de wrapper wordt gekoppeld aan een object, bevat het twee extra parameters die werden meegegeven bij het aanmaken van de wrapper, namelijk `concreteEventName' die de naam van het event geeft dat juist getriggered werd en `partName' die een identifier is voor het object dat in het event ge\"interesseerd is. Wanneer het desbetreffende event nu tijdens het runnen van de code wordt aangeroepen, bevat het deze twee extra parameters. \lstset{basicstyle=\footnotesize, frameround=fttt, numbers=left, numberstyle=\tiny, language=[Sharp]C, breaklines=true} \begin{lstlisting}[float, frame=bt, caption=Wrapper rond een event handler, label=wrapper] virtual public EventHandler CreateHandlerWrapper(string concreteEventName, string partName) { return delegate(object sender, EventArgs e) { Execute(sender, e, concreteEventName, partName); }; } \end{lstlisting} \subsection{De linker} Hoe vangen we nu wijzigingen van een property op? Als de ontwikkelaar ge\"interesseerd is in het aanvinken van checkbox A, dan worden alle events van checkbox A geregistreerd in de linker via reflectie. Wanneer \'e\'en van deze events zich voordoet, dan weten we dat er iets verandert is aan die checkbox. Het enige dat we dan nog moeten doen, is kijken of de conditie evalueert naar \textit{waar}. Het registeren van alle events zorgt natuurlijk voor heel wat overhead, de condities worden vaak gecheckt op momenten wanneer het niet nodig is. Maar er blijft een voordeel ten opzichte van polling. Wanneer een interface idle is, zal er ook niets gecheckt worden. Alles blijft stil totdat de gebruiker beslist om terug te werken met de interface. De rest van de linker blijft hetzelfde. Als we een \texttt{$<$event$>$} element tegenkomen, wordt dit via reflectie aan het desbetreffende object (widget) gekoppeld. Het linken van een conditie gebeurt nu niet langer meer in de backends, maar is verplaatst naar de kern. Er zijn twee interfaces, namelijk \texttt{IEventLinker} en \texttt{IEventLink} waarvan de volgende klasses zijn afgeleid (zie ook figuur \ref{link_linker}): \begin{description} \item[EventLinker] is afgeleid van \texttt{IEventLinker} en zorgt voor het linken van een conditie. Hiervoor gebruikt hij de klasse \texttt{ConditionLinker} die alles afhandelt. \item[EventLink] is afgeleid van \texttt{IEventLink} en zorgt voor het nakijken of een conditie evalueert naar \textit{waar}. Hij gebruikt hiervoor de klasse \texttt{ConditionChecker}. \end{description} Tijdens het linken wordt iedere conditie opgeslagen in de condition manager (klasse \texttt{ConditionManager}), die nu verder besproken zal worden. \begin{figure}[h] \center \includegraphics[scale=0.75]{images/linker.jpg} \caption{Het linken en checken van events} \label{link_linker} \end{figure} Doordat het linken nu in de core gebeurt en niet meer in de backends is 1/3 van de klasses uit de backends verdwenen. Met andere woorden, de backends hebben minder verantwoordelijkheden gekregen. \subsection{De manager} \label{de_manager} De manager is een klasse die alle events opvangt en afhandelt. Het bevat alle condities van de volledige interface. Wanneer een event getriggered wordt, dan zal een centrale functie in deze klasse aangeroepen worden. Dit is de functie te vinden in listing \ref{condition_function}, zie ook figuur \ref{condition_fig}. Deze functie heeft 2 extra parameters zoals besproken in sectie \ref{an_delegates}. Het event dat zich juist heeft voorgedaan, wordt in een tabel geplaatst, waar het een bepaald aantal seconden zal worden bijgehouden. In mijn implementatie is dit 5 seconden. Dit is nodig omdat er conditions ge\"interesseerd kunnen zijn in \'e\'en of meerdere events. Door ze bij te houden in een tabel, kunnen altijd de events worden opgevraagd die de afgelopen seconden zijn gebeurt. Vervolgens worden alle condities afgegaan. Voor iedere conditie wordt gekeken of het aan de voorwaarden voldoet. Hiervoor is de functie \texttt{CheckCondition()} ge\"implementeerd. Deze functie loopt alle voorwaarden van de conditie af en kijkt of deze evauleren naar \textit{waar} (regels voor evaluatie zijn besproken in sectie \ref{eval_conditions}). Er wordt ook een boolean bijgehouden om aan te geven of de actie, horende bij de conditie al is uitgevoerd. Anders zou deze actie meerdere keren worden uitgevoerd. De boolean wordt gereset wanneer de conditie evauleert naar \textit{niet waar}. \lstset{basicstyle=\footnotesize, frameround=fttt, numbers=left, numberstyle=\tiny, language=[Sharp]C, breaklines=true} \begin{lstlisting}[float, frame=bt, caption=Execute functie, label=condition_function] public void Execute(Object sender, EventArgs e, string eventName, string partName) { CheckEventsInterested(eventName, partName); } \end{lstlisting} \begin{figure}[h] \center \includegraphics[scale=0.75]{images/event_triggered.jpg} \caption{Het plaatsvinden van een event} \label{condition_fig} \end{figure}