„Unit-Testing“ mit Sitecore

Viele Software-Entwickler dürften mittlerweile um die Wichtigkeit und Nützlichkeit von Unit-Tests Bescheid wissen. So erleichtert der Einsatz von Unit-Tests beispielsweise das Schreiben robuster und flexibler Software. Ausserdem dienen die Tests beim Refactoring als „Sicherheitsnetz“, um das „äussere Verhalten“ der Software nicht unbeabsichtigt abzuändern.

Allerdings bringt das Schreiben von Unit-Tests auch einiges an Mehraufwand mit sich und in gewissen Umgebungen scheint das Schreiben von Unit-Tests
sehr schwierig oder gar unmöglich zu sein. Gerade auch bei Web-Applikationen mit Sitecore scheint das Schreiben von Unit-Tests ein schwieriges Unterfangen zu sein, da die Sitecore-API „im Hintergrund“ auf Datenbanken zugreift und einen Web-Context voraussetzt.

In diesem Artikel wollen wir aufzeigen, wie man für Sitecore-Code mit einem pragmatischen Ansatz trotzdem relativ einfach automatisierte Tests schreiben kann.

Automatisierte Tests mit einem Web-Testrunner

Alistair Deneys hat eine sehr schöne Reihe von Posts zum Thema „Unit-Testing mit Sitecore“ veröffentlicht. Im Buch „Professional Sitecore Development“ wurde ausserdem ein ganzes Kapitel dem Thema „Testing“ gewidmet, welches ebenfalls von Deneys verfasst wurde. Deneys diskutiert in seinen Blogs und im Buch „Professional Sitecore Development“ verschiedene Möglichkeiten, um Code, der die Sitecore-API verwendet, testen zu können.

Ein sehr pragmatischer Ansatz, um Sitecore-Code zu testen, besteht darin, die Tests in einem Web-Testrunner im Sitecore-Context auszuführen. Mit dieser Technik bleibt das (teilweise mühsame und zeitaufwändige) Mocking von Datenbankzugriffen und dem Web-Context erspart. Wenn die Tests in einem Web-Testrunner ausgeführt werden, haben wir in den Tests vollen Zugriff auf die Sitecore-Datenbanken und den Web-Context.

Wenn wir Tests schreiben, die in einem Web-Testrunner ausgeführt werden, dürfen wir streng genommen allerdings nicht mehr von „Unit-Tests“ sprechen, sondern viel mehr von „automatisierten Tests“ (siehe Definition „Unit-Test“ von Roy Osherove).

Ein einfacher Web-Testrunner, welcher auf NUnit basiert, kann bei Deneys gratis heruntergeladen werden (Link Web-Testrunner). Bei dem Web-Testrunner handelt es sich im Wesentlichen um eine ASPX-Page, die in das Visual-Studio-Sitecore-Web-Projekt eingebunden werden kann. Im Code-Behind dieser ASPX-Page referenziert man dann die DLL des Testprojektes, in welchem sich die automatisierten Sitecore-Tests befinden.

Folgende Abbildung zeigt ein Beispiel des Web-Testrunners in Aktion (Quelle).

Ein einfaches Code-Beispiel

Deneys geht in seinen Posts auf verschiedene „Typen“ von Tests ein. Etwas vereinfacht können wir zwischen folgenden beiden Test-Typen unterscheiden:

  1. Testen von Präsentationskomponenten (Layouts, Sublayouts, Usercontrols, …)
  2. Testen von Code, der auf die Sitecore-API zugreift (beispielsweise Helper-Klassen, um Sitecore-Items zu bearbeiten/auszulesen/etc.)

Folgendes Listing zeigt ein einfaches Beispiel, wie ein Test für den Test-Typ 2 aussehen könnte.

[TestFixture]
[Category("Util Tests")]
public class TestClass
{
   private Item m_root, m_child1, m_child2, m_child3 = null;

   [SetUp]
   public void TestFixtureSetUp()
   {
      var home = Sitecore.Context.Database.GetItem("/sitecore/content/home");
      var template = Sitecore.Context.Database.Templates["User Defined/Page"];

      using (new SecurityDisabler())
      {
         m_root = home.Add("root", template);

         m_child1 = m_root.Add("Child 1", template);
         using(new EditContext(m_child1))
         {
            m_child1["title"] = "Child 1 Title";
         }

         m_child2 = m_root.Add("Child 2", template);
         m_child3 = m_root.Add("Child 3", template);
      }
   }

   [TearDown]
   public void TestFixtureTearDown()
   {
      using (new SecurityDisabler())
      {
         m_root.Delete();
      }
   }

   [Test]
   public void TitleNotEmptyTest()
   {
      string title = Util.GetTitle(m_child1);
      Assert.AreEqual("Child 1 Title", title);
   }

   [Test]
   public void TitleEmptyTest()
   {
      string title = Util.GetTitle(m_child2);
      Assert.AreEqual("", title);
   }
}

Der Code im obenstehenden Beispiel zeigt, wie wir in der Setup-Methode eine „Dummy-Item-Struktur“ für die Tests mit der Sitecore-API aufbauen. In der Teardown-Methode wird diese Dummy-Item-Struktur wieder gelöscht. In den Tests können wir diese Dummy-Items dann verwenden, um unseren Code (im obigen Beispiel die Methode GetTitle der (Helper-)Klasse Util) zu testen.

Fazit

In diesem Artikel haben wir gesehen, dass man mit einem pragmatischen Ansatz auch für Sitecore-Solutions relativ einfach automatisierte Tests schreiben kann. Die Tests werden dabei in einem Web-Testrunner im Sitecore-Context ausgeführt, wodurch wir in den Tests vollen Zugriff auf die Sitecore-Datenbanken und den Web-Context haben. Das zeitaufwändige Mocking von Datenbankzugriffen und dem Web-Context erübrigt sich durch das Ausführen der Tests in einem Web-Testrunner.

Custom Gutter für die Anzeige von fehlenden Item Sprach-Versionen

Wir beschreiben hier, wie eine häufige Kundenanforderung gelöst werden kann, um zu sehen ob ein Item in der aktuell aktivierten Sprache vorhanden ist, oder nicht. Out of the Box bietet Sitecore nur den Gutter „Missing Versions“ an, welcher sich jedoch darauf spezialisiert hat alle Items hervorzuheben, welche irgend eine Lücke in einer Sprache oder Version besitzen – unabhängig von der gewählten Sprach-Version. Weiterlesen

Splunk for Sitecore Logs

Was ist Splunk?

Splunk ist ein Log-, Monitoring- und Reporting-Tool. Es kann verschiedenste Textdateien, wie Log-Dateien oder andere Daten von Applikationen oder Servern, einlesen und in einem durchsuchbaren Speicher ablegen. Splunk bietet ein komfortables Web-Interface, mit dem die indexierten Daten durchsucht werden können sowie Warnmeldungen und grafisch ansprechende Diagramme generiert werden können.

Sitecore Log Source Type

Splunk liest die einzelnen Files nach einem vordefinierten Muster ein und versucht so, die einzelnen Events zu erkennen. Diese Muster werden Source Types genannt und sind essentiell wichtig, damit die Analyse von Log-Files überhaupt funktionieren kann. Leider existiert für Sitecore bzw. log4net kein Source Type. So haben wir selber einen solchen erstellt und können nun die Sitecore Logs sauber indexieren. In der Datei etc/system/local/props.conf des Splunk-Programm-Verzeichnisses muss dazu folgender Eintrag gemacht werden:

[Sitecore Log]
BREAK_ONLY_BEFORE = \S+\s\d{2}:\d{2}:\d{2}
NO_BINARY_CHECK = 1
SHOULD_LINEMERGE = true
pulldown_type = 1

Sobald die Konfigurationsdatei angepasst und Splunk neu gestartet wurde, kann beim Hinzufügen von neuen Datenquellen der Source Type „Sitecore Log“ ausgewählt werden:

Splunk ist ein nützliches Tool, um viele Log-Files komfortabel zu durchsuchen und zu analysieren. Die zusätzlichen Funktionen wie beispielweise das automatische Alarmieren bei gewissen Events, machen den Einsatz in einer Produktivumgebung mit grossem Datenvolumen interessant. Zu erwähnen ist ausserdem Splunk Storm, welches die cloud-basierte Version von Splunk darstellt.

SEO Toolkit – Was steckt dahinter?

Suchmaschinenoptimierung mit Sitecore

Von Keywords über Meta Tags, Descriptions und vieles mehr, kann Ihre komplette Webseite mit dem SEO Toolkit schnell und einfach analysiert und suchmaschinenfreundlich verwaltet werden.

SEO Toolkit

Verschiedene Register helfen dem Autor den Überblick über nachfolgende SEO relevanten Themen zu behalten:

Page Information:

Dieses Register bietet einen kurzen Überblick über SEO relevante Inhalte der jeweiligen Seite. So erkennen Sie auf einen Blick wo das SEO Toolkit noch Suchmaschinen-Optimierungspotential sieht.

Text Only View:

Der Text Only View stellt die aktuelle Seite aus Sicht der Suchmaschine dar. So werden jegliche Designs und Bilder entfernt, um den indexierten Inhalt zu sehen. Überschriften werden in grösseren Schriftarten dargestellt, da diese auch von der Suchmaschine besser bewertet werden. Links werden in Form von unterstrichenem Text und Bilder, welche einen gepflegten Alternativtext haben, werden mit eckigen Klammern [Alternativtext] dargestellt.

Key Words:

Die aufgelisteten Keywords in diesem Register, sind Wörter welche im Seiteninhalt am Häufigsten benutzt wurden. Zusätzlich wird in % die Häufigkeit des Wortes in Relation mit dem gesamten Seiteninhalt angegeben. Per Klick können Sie dann das jeweilige Keyword in einer Suchmaschine (Google, Yahoo oder Bing) suchen und direkt Ihr aktuelles Rating beurteilen.

Search Engines:

Hier erhalten Sie per Klick von drei Suchmaschinen (Google, Yahoo und Bing) eine Liste an Seiten, welche auf die aktuelle Seite verlinken. Da die Anzahl an „incoming Links“ Einfluss auf Ihr Ranking hat, ist die Wichtigkeit dessen nicht zu unterschätzen.

Headings:

In diesem Register werden alle Überschriften der aktuellen Seiten aufgelistet. So können Sie auf einen Blick den Inhalt aktueller Headlines überprüfen und gegebenfalls optimieren, um die Relevanz für Suchmaschinen zu erhöhen. Mittels Klick auf die jeweilige Überschrift gelangen Sie direkt zur dementsprechenden Überschrift.

Images:

Im Bezug auf SEO ist nicht das Bild entscheidend, sondern vielmehr der Alternativtext für Suchmaschinen. Deshalb werden in diesem Register alle Bilder mit Alternativtext, URL und Grösse aufgelistet. Jene Bilder welche keinen Alternativtext enthalten werden zuerst gelistet. Mittels Klick gelangen Sie auch hier direkt zum Bild, um den Alternativtext zu pflegen.

Links:

Hier werden alle Links der aktuellen Seite gelistet. Das Toolkit legt hierbei besonderen Wert auf die Funktionsweise der Links. Alle „broken links“ werden auch hier als Erstes aufgelistet.

Meta Tags:

Hier werden die Meta Tag Informationen der jeweiligen Seite aufgelistet. Diese enthalten unter anderem die Description, Keywords und Copyright Informationen. Besonderen Wert sollte auf die Pflege der „keyword meta tags“ gelegt werden, da diese von der Suchmaschine zur Beurteilung der Relevanz der Seite herangezogen werden.

Mit dem einem durchdachten Konzept, dessen konsequenter Umsetzung und der Unterstützung des SEO Toolkits von Sitecore  sind die wichtigsten Voraussetzungen für eine wirksame SEO gegeben.

Multi Device Simulation.

Single Device war gestern – Multi Device ist heute

Im Zeitalter der Multi Devices ist es schlichtweg fast unmöglich Webseiten nur noch auf ein einziges Device zu optimieren. So stellt sich auch für viele Content Autoren immer häufiger die Frage: „Wie sieht die aktuelle Seite denn auf Smartphone, Tablet oder TV aus?“

Das Ende 2012 gelaunchte Sitecore 6.6 bietet hierfür einen Device Simulator. Autoren können somit im Page Editor im Register „Experience“ das entsprechende Device auswählen und die Simulation durchführen. Das Ergebnis des jeweiligen Devices ist zwar nicht pixelgenau, dennoch gibt es einen guten ersten Eindruck, wie sich die Seite auf dem jeweiligen mobilen Gerät verhält. Die Simulation ermöglicht es auch durch die ganze Webseite zu navigieren, zu scrollen (vertikal und horizontal) und das Device zu drehen.

Sitecore Device Simulator

Ein Schritt in die Zukunft. Wir unterstützen Sie gerne.

Sitecore ajaxified – Die Favoritenliste

In einem aktuellen Projekt wollten wir dem (anonymen) Nutzer die Möglichkeit geben einzelne Produkte in eine Favoritenliste abspeichern zu können um diese bei einem späteren Besuch der Webseite wieder abrufen zu können. Das Ganze sollte möglichst ohne reload der Seite realisiert werden.

Mithilfe von .Net 4.0 und jQuery lassen sich ohne großen Aufwand Ajax Funktionalitäten für Sitecore Webseiten umsetzen.

Dazu benötigen wir drei Dinge:

  1. Cookie handling
  2. Einen Sitecore Service
  3. Javascript

Im folgenden Abschnitt wird eine beispielhafte Implementierung der Favoritenliste vorgestellt.

Die Favorites Klasse stellt uns Funktionen zur Verfügung, die uns vereinfachten Zugriff auf die vom HttpContext übergebenen Cookies liefert, bzw. die manipulierten Cookies zurück an den Nutzer liefert.

namespace Namics.Internet.Core
{
    using System.Collections.Generic;
    using Sitecore.Data;
    using System.Web;
    using System.Linq;
    using Sitecore.Data.Items;
 
    public static class Favorites
    {
        private const string FAVORITE_COOKIE_STRING = "FAVORITE_COOKIE";

        private static HttpCookie FavoriteCookie
        {
            get
            {
                if (HttpContext.Current.Request.Cookies[FAVORITE_COOKIE_STRING] == null)
                {
                    HttpContext.Current.Request.Cookies.Add(new HttpCookie(FAVORITE_COOKIE_STRING));
                }

                return HttpContext.Current.Request.Cookies[FAVORITE_COOKIE_STRING];
            }
        }

        public static void Add(Item pItm)
        {
            FavoriteCookie.Values.Add(pItm.ID.ToString(), string.Empty);
            Update();            
        }

        public static void Remove(Item pItm)
        {
            FavoriteCookie.Values.Remove(pItm.ID.ToString());  
            Update();      
        }

        public static void Clear()
        {
            FavoriteCookie.Values.Clear();
            Update();
        }

        public static IEnumerable<Item> GetAll()
        {
            return FavoriteCookie.Values.AllKeys.Select(key => Sitecore.Context.Database.GetItem(ID.Parse(key)));
        }

        private static void Update()
        {
            HttpContext.Current.Response.Cookies.Add(FavoriteCookie);
        }
    }
}

 

Ein Sitecore Service soll nun die Funktionen der Favorites Klasse dem Javascript Client zur Verfügung stellen.
Durch die Einfachheit des Services und nicht für die Öffentlichkeit bestimmten Verwendung der API konnten wir das im .Net 4.0 eingeführte ExpandoObject verwenden um den Code kurz zu halten (und uns z.B. das Schreiben einer serialisierbaren Klasse zu sparen).

namespace Namics.Internet.Core.Handlers
{
    using System.Dynamic;
    using System.Web;
    using Newtonsoft.Json;
    using Sitecore.Data;
    using System.Linq;
   
    public class FavoritesServiceHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext pContext)
        {
            pContext.Response.ContentType = "application/json";
            dynamic response = new ExpandoObject();

            var command = HttpContext.Current.Request.QueryString["cmd"];
            var idStr = HttpContext.Current.Request.QueryString["id"];        

            if (!string.IsNullOrEmpty(idStr))
            {
                var item = Sitecore.Context.Database.GetItem(ID.Parse(idStr));

                switch (command)
                {
                    case "add":
                        Favorites.Add(item);
                        break;
                    case "remove":
                        Favorites.Remove(item);
                        break;
                }
            }
            else
            {
                switch (command)
                {
                    case "clear":
                        Favorites.Clear();                      
                        break;
                    case "get":
                        response.Result = Favorites.GetAll().ToList();                      
                        break;
                }
            }
           
            response.Success = true;
            pContext.Response.Write(JsonConvert.SerializeObject(response));
        }
    }
}

 

Den Service müssen wir in der Sitecore.config und der Web.config noch wie folgt registrieren.

In der Sitecore.config im Abschnitt

 <customHandlers> 

fügen wir diese Zeile hinzu:

<handler trigger="~/service/favorites" handler="FavoritesServiceHandler.ashx"/> 

und in der Web.config im Abschnitt

 <httpHandlers>
<add verb="*" path="FavoritesServiceHandler.ashx" type="Namics.Internet.Core.Handlers.FavoritesServiceHandler, Namics.Internet.Core" />

 

Nun fehlt noch der Clientseitige Teil, der mit jQuery in wenigen Zeilen umgesetzt werden kann.

$('#clear').bind("click", function () {
 $.ajax({
   url: 'http://mywebsite/service/favorites?cmd=clear',
   success: function (data) {
    if (data.Success) {
     alert("Gelöscht!");
    }
   }
 });
});

 

So konnte die gewünschte Funktionalität in wenigen Schritten und ohne grösseren Aufwand in Sitecore umgesetzt werden.

Neues Sitecore Modul überwacht die Einhaltung von Standards

Ein neues Sitecore Modul prüft Webseiteninhalte automatisiert auf Einhaltung von Standards sowie auf unternehmenseigene und gesetzliche Regularien. Basis dieses Moduls ist die renommierte „Compliance Sheriff“-Applikation von HiSoftware.

Mit diesem Modul ist es möglich, Web-Inhalte automatisiert nach formellen, gesetzlichen und qualitativen Kriterien zu überprüfen, noch bevor sie publiziert werden. Die Kontrolle von regulativen und eigenen Bestimmungen (z.B. Schreibweise von Namen, Branding-Spezifika etc.) erfolgt regelbasiert.

Weitere Informationen zu diesem neuen Sitecore Modul sind in der Sitecore Pressemeldung zu finden.

Unser Wissen für Euren Erfolg – Namics goes Open Source

Als wir uns vor einigen Jahren dafür entschieden haben, im .Net Umfeld mit dem Content Management System „Sitecore“ zu starten, gingen wir wohl – wie bei jeder Evaluation, ein gewisses Risiko ein. Erfüllt dieses CMS die Anforderungen der Kunden? Lässt … Weiterlesen

mobilezonecom.ch erhält einen neuen Auftritt

In Rekordzeit wurde der Internetauftritt von mobilezonecom.ch mit dem neuen Festnetz- und Internet-Angebot „Call & Surf“ auf Basis von Sitecore auf die Beine gestellt und ebenso schnell wurde der Inhalt durch mobilezone erfasst.

Dank der Optimierung des PageEditors, kann mobilezone ca. 90% des Inhalts im PageEditor pflegen. Dies ermöglicht ein extrem effizientes abfüllen von Inhalten und die Vorschau der Seite im Preview-Modus erübrigt sich auch gleich.

Besonders nett gelöst ist die Platzierung der SEO Eingabefelder, welche gleich zu Beginn der Seite gepflegt werden können. Eine neue Seite lässt sich mit zwei Klicks erstellen und gleich danach kann der Autor den Navigationspunkt entsprechend benennen. Flyouts werden auf einer neuen Seite geöffnet, damit der Autor die gesamte Breite der Arbeitspalette zur Verfügung hat. Schnell und einfach kann man mittels Sprachwechsler durch die verschiedenen Sprachen navigieren, um Inhalte darin abzufüllen. Mit wenigen Klicks legt man ein Formular an der gewünschten Stelle an und pflegt dessen Felder mittels Form Designer. Das gleiche gilt für Kundenspezifischen Module, sowie allen Teasern, welche im Rahmen dieses Projekt entwickelt wurden.

Viele dieser „Gadgets“ sind einfach umzusetzen und für die Inhaltsmigration nur von Vorteil.

Namics Hamburg war verantwortlich für die Frontend- und Backendumsetzung. Konzept und Design wurde durch mobilezone geliefert.

Hier gehts zur Webseite: http://www.mobilezonecom.ch