Visar inlägg med etikett Unit Test. Visa alla inlägg
Visar inlägg med etikett Unit Test. Visa alla inlägg

måndag, augusti 24, 2009

Dags att använda nUnit igen...

För ett par dagar sedan började jag jobba med NUnit igen. Sista tiden har jag använt mig av Visual Studios unit testing men nu ska vi använda oss av NUnit i projektet som jag sitter i. Det första jag gjorde var att lägga till tangentbordsgenvägar för att kunna köra respektive debugga det test som är i fokus (CTRL +R, T och CTRL + R + T) samt genväg för att köra alla test i en solution (CTRL + R, A). Can’t live without them! Som tur var så använder jag mig av ReSharper som också har en integrerad test runner i Visual Studio.

Sedan skapade jag ett nytt class library och la till referens till nunit.framework och konverterade ett par test som var skrivna med Visual Studios testramverk till NUnit.

En sak som jag alltid har gillat med NUnit är deras Asserts som är mycket mer avancerade än Visual Studios. Det är kanske inte alltid man behöver det men det ökar läsbarheten att kunna skriva:

Assert.That(expected, Is.EqualTo(actual));

Istället för:

Assert.AreEqual(expected, actual);

Så efter att ha copy/paste:at in mina tester och bara uppdaterat attributen till classen och testmetoderna var det bara att köra.

Alla test fungerade bra i NUnits egna testrunner men ett av testen misslyckades i ReSharpers integrerade testrunner i Visual Studio. Det test som rapporterades som misslyckat var ett test som hade attributet [ExpectedException]. Det visade sig att ReSharper inte kan hantera det attributet. Istället för att använda ett attribut för att markera att man förväntar sig ett fel från en metod får man använda sig av en annan assert från NUnit:

var ex = Assert.Throws(() => target.MethodThatWillReturnException());

tisdag, september 30, 2008

Scrum med ITMaskinen

I fredags hade jag unge herr Deurell en föreläsning för ITMaskinen om agile, Scrum och hur man kan använda Microsofts verktyg för att lyckas. Min roll var så klart att prata om agile och Scrum och Micke pratade om TFS och vikten av test med hjälp av Team System.

Läs mer i inlägget De tre vise männen coh Scrum på ITMaskinens eminenta bloggsida.

fredag, maj 02, 2008

Plugin-pattern på webben

Martin Fowler har i sin bok Patterns of Enterprise Application Architecture beskrivit ett plugin patter som man kan använda för att länka ihop applikationer genom konfiguration istället för vid kompilering. Min tanke var att bygga en webbapplikation, typ en portal, som sedan blir medveten om att andra applikationer existerar bara genom en konfigurering istället för att man måste känna till den vid utveckling. Min vision var att kunna utveckla och uppgradera portalen för sig och sedan utveckla och uppgradera applikationer för sig.

Jag började med att definiera ett interface som varje applikation måste implementera. Det interfacet ska kunna leverera information om applikationen i fråga:

    public interface IApplicationInfo

    {

        string ApplicationName { get; set; }

    }

 

Sedan la jag till en PluginFactory med en statisk metod getPlugin. Den metodens uppgift var att läsa in assemblyt (snyggt ord) från disk och skapa en instans av den klass som implementerar IApplicationInfo och returnera denna...

public static IApplicationInfo getPlugin(string assemblyName)

{

var assembly = Assembly.LoadFrom(assemblyName);

var assemblyTypes = from a in assembly.GetTypes()

                    select a;

 

foreach (var t in assemblyTypes)

{

    var o = Activator.CreateInstance(t);

    if (o is IApplicationInfo)

        return o as IApplicationInfo;

}

return null;

}

 

Först placerade jag min PluginFactory i samma Visual Studio 2008 projekt som Portalen men det gjorde att mina enhetstester mot getPlugin blev otroligt sega att köra eftersom att den måste starta igång webservern först. Det blev dock betydligt bättre när jag flyttade ut den till ett eget class-library. Ett härligt bevis på hur test-driven utveckling gör att man fattar beslut tidigt som gör att ens arkitektur blir mer testbar!

Nästa steg var att lägga till en AppSetting i min web.config för varje applikation som jag vill att portalen ska känna till och använde mig av en LINQ-fråga för att hämta ut dessa:

var applications = from a in ConfigurationManager.AppSettings.AllKeys

                   where a.StartsWith("PortalApplication")

                   select new { AssemblyName = ConfigurationManager.AppSettings[a] };

 

Grymt coolt! Refelction, LINQ, plugin-patterns och allt möjligt coolt men sen då? Vad har jag vunnit med det här jämfört med att bara lägga in den här informationen i web.config eller i en databas. Hur ska jag nu få mina applikationer att agera i portalen som om de var en del av portalen från första början?

Ju mer jag funderar på det hela desto mer ser det ut som att det är Facebook jag vill bygga (fast utan den sociala delen)... För det är ju precis det Facebook är, en portal med viss gemensam funktionalitet och ett antal tjänster som sedan applikationsutvecklare kan nyttja för att bygga egna applikationer som jackas in i portalen. Så hur har Facebook löst interaktionen mellan en applikation och portalen? Kör varje applikation i en IFrame eller? Är det någon som vet??

tisdag, oktober 02, 2007

NUnit Asserts i VS2008 unit testing

Med NUnit 2.4 så kom möjligheten att använda en ny modell för hur man hanterar Asserts, en Constraint-baserad modell. Tidigare var man tvingad att använda olika asserts beroende på vad man vill testa (som t ex Assert.IsTrue() eller Assert.AreEqual) men nu kan man istället använda sig av Assert.That(). En av överlagringarna i Assert.That tar ett Constraint-objekt som inparameter. Constraint-objekt ligger i ett eget namespace i nunit.framework.dll som heter NUnit.Framework.Constraints.

Utöver det så finns även ett namespace som heter NUnit.Framework.SyntaxHelpers. SyntaxHelpers innehåller en klass som heter Is (eller Iz för VB.Net) och alla metoder i Is returnerar ett object av typen Constraint.

Detta gör att man kan skriva asserts av typen:

Assert.That(strMyName, Is.EqualTo("Björn Eriksen").IgnoreCase);

eller

Assert.That(11111.3, Is.EqualTo(11111.31).Within(0.1));

eller

Assert.That(50, Is.Not.EqualTo(100));





Det här sättet att skriva asserts tycker jag är väldigt trevligt och man saknar det snabbt om man måste gå tillbaka och skriva på det "gamla" sättet.

I Visual Studio 2008 finns inte något inbyggt stöd för att använda constraints-baserade asserts men det är ju onekligen en trevlig IDE att använda för unit testing så vad gör man...?

Det man kan göra är att använda NUnit constraints based asserts i Visual Studios unit testing-ramverk!

För att få till det hela på ett smidigt sätt så måste man plocka bort using-referensen till Microsoft.VisualStudio.TestTools.UnitTesting; och ersätta den med:

using NUnit.Framework;

using NUnit.Framework.SyntaxHelpers;




Anledning till detta är att klassen Assert finns med i både NUnit.Framework och i Microsoft.VisualStudio.TestTools.UnitTesting, så kompilatorn vet inte vilken den ska välja. För enkelhetens skulle bör man därför plocka bort using-referensen till Microsoft.VisualStudio.TestTools.UnitTesting istället för den till NUnit. Då blir det enklare när man ska skriva Asserts i sina test-metoder.

Effekten blir då den att, för attribut och typer som man ska referera från Microsofts test-ramverk så måste man ha kompletta sökvägar t ex:

[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod()]



I och med Visual Studio 2008 så kommer unit testing att vara med i Professional-versionen och förhoppningsvis leder det till att det blir enklare att införa unit testing i projekten!

fredag, januari 26, 2007

Compare objects in unit test

Today I wanted to create some unit tests for a object relationship mapper that Connecta developed for a client. The method I wanted to test was a find method that takes an id for an entity and returns that entity from the database. The entity that I searched for was created in a static method marked with the [ClassInitialize()] attribute.

By the way, I use Team System for unit testing.

So, how do I compare the objected that I created with the object that I got from the database? Will I be happy with just comparing what ToString returns or do I take a random number of properties and compare them? No, the only reasonable thing to do is to compare the value of every property on the objects.

To do this I created a new static class in my test project called
ObjectComparer
. ObjectComparer has one method called CompareObjects that takes the two objects to compare as in-parameters. Then I use reflection to find the properties on the object and compare the value of every property in the two objects. That worked really well but I soon realized that I needed a way to exclude properties from the compare method. For instance there can be a datetime field that holds a datetime for when the record was created in the database. This field will never be the same in a compare and therefore needs to be ignored. So I added another parameter that will hold a generic list that contains the names of the properties to ignore: List<string> IgnoreList.
CompareObjects returns another object called ObjectCompareResult that contains two properties, a Boolean containing the result of the compare and a string containing the possible error message if the compare returns false.

Here is the code for the method CompareObjects:

public static ObjectCompareResult CompareObjects(object obj1, object obj2, List<string> IgnoreList)
{
Type objectType1 = obj1.GetType();
PropertyInfo[] propertyInfos = objectType1.GetProperties();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (IgnoreList == null || (IgnoreList != null && !IgnoreList.Contains(propertyInfo.Name.ToString())))
if (!propertyInfo.GetValue(obj1, null).Equals(propertyInfo.GetValue(obj2, null)))
return new ObjectCompareResult(false, String.Format("The value of the property '{0}' is not the same in the two objects. Value from obj1 = '{1}'. Value from obj2 = '{2}'",
propertyInfo.Name.ToString(),
propertyInfo.GetValue(obj1, null),
propertyInfo.GetValue(obj2, null)));
}
return new ObjectCompareResult(true);
}



And here is the code for the unit test:

[TestMethod()]
public void FindTest()
{
MyStorage target = FrameworkUnitTest.Framework_Storage_MyStorageAccessor.CreatePrivate();
MyEntity expected = myEntity; //Created in the ClassInitialize
MyEntity actual = target.Find(myId);
List ignoreList = new List();
ignoreList.Add("DateCreated");

ObjectCompareResult result = ObjectComparer.CompareObjects(expected, actual);

Assert.IsTrue(result.CompareResult, result.CompareMessage);
}


Thanks to my peers for help when it comes to reflection and comparing object values!