Soms loop je in je zoektocht naar een framework of, zoals in dit geval bij toeval, tegen een framework aan waarvan je denkt: Ja, dit is leuk en handig om te gebruiken in mijn ontwikkel projecten. Bij mij was dat het geval toen ik per ongeluk tegen een cursus over het SpecsFor BDD framework aanliep tijdens het scannen van interessante cursussen op PluralSight).

SpecsFor is een framework dat gebruik maakt van de volgende andere bekende (test) frameworks:

  • ExpectedObjects
  • Moq
  • Structuremap
  • Should
  • NUnit

SpecsFor is zowel geschikt om te gebruiken voor unit testen als voor integratie testen. In dit artikel zullen we eerst de focus leggen op unit testen.

In dit artikel wordt als voorbeeld gebruik gemaakt van een eenvoudige MVC web applicatie waarin we Formule 1 teams kunnen samenstellen.

De source code gebruikt in dit artikel is terug te vinden op github.

SpecsFor is een BDD framework geschreven om gedrag te testen, SpecsFor doet dit door het toepassen van de Given, When, Then methodiek.

Een van de vereisten van onze applicatie is dat een team naam slechts eenmaal mag voorkomen. Dat betekent dat we twee scenario’s kunnen bepalen, te weten:

  • Succes scenario: een team met een nog onbekende naam is toegevoegd aan de teams collectie.
  • Fail scenario: een team met een reeds bestaande naam wordt toegevoegd aan de teams collectie.

De scenario’s welke we met behulp van ‘SpecsFor’ zullen gaan testen maken gebruik van de classes welke in de volgende paragraaf zullen worden beschreven.

Class implementaties

Voor het ophalen en wegschrijven van onze data gebruiken we een eenvoudige repository class welke de interface ‘IRepository<TEntity>’ implementeert en gebruik maakt van een Entity framework Core context.

Repository interface

Teams repository class

FormulaOneContext class

Voor het opslag mechanisme gebruiken we Entityframework Core. Onze context class welke geïnjecteerd wordt in onze repository class is de FormulaOneContext class:

TeamsManager class

Met deze class definities op hun plaats kunnen we onze eerste testscenario gaan uitwerken met behulp van SpecsFor.

Tip:
Als je gebruik maakt van ReSharper, dan kun je via de ReSharper Extensions, templates voor SpecsFor installeren. Deze templates helpen je bij het opzetten van een SpecsFor test class.

System Under Test

De eerste stap welke we moeten nemen is het toevoegen van een nieuw class library project aan onze solution. In dit project zullen we onze tests gaan definiëren. De volgende stap is om het ‘SpecsFor’ nuget package toe te voegen aan ons test project. Het eenvoudigst doe je dit door naar de package Manager console in Visual Studio te gaan en het volgende commando uit te voeren: “install-package SpecsFor”. Denk hierbij aan het selecteren van het correcte default project, anders worden de nuget packages aan het verkeerde project toegevoegd.

Nu we het SpecsFor framework hebben geïnstalleerd kunnen we gaan kijken welk gedrag van onze applicatie we willen gaan testen.

In onze unit testen gaan we een service class genaamd ‘TeamsManager’ testen welke voor ons een nieuw team zal toevoegen aan onze team collectie. Het eerste scenario zal het succesvol toevoegen van een nieuw team zijn.

  • Voeg een specs class ‘TeamManagerSpecs’ toe aan het test project. Dit zal de outer class zijn voor onze specificaties.
  • Voeg nu binnen deze class een geneste class toe met invulling van het Given onderdeel en laat deze class een afgeleide zijn van de ‘SpecsFor<SystemUnderTest>’ class. Waarbij <SystemUnderTest> het generieke type dient te zijn van de class welke we willen gaan testen.

Dit kan er als volgt uitzien:

Om nu de actie uit te kunnen voeren op het System Under Test, in ons geval de ‘TeamsManager’ class, dienen we de ‘When’ methode te overschrijven.

Nu kom het uiteindelijke doel in zicht…. testen van de uitkomst. Hiervoor dienen we een ‘Then’ methode te schrijven. Aangezien dit een NUnit test methode dient te zijn, moeten we deze methode decoreren met het [Test] attribuut.

De “AddTeam” methode is een methode welke geen resultaat retourneert, dus deze methode kunnen we enkel testen op de program flow binnen de methode. Het verifiëren van de program flow kunnen we doen met behulp van Moq. De SpecsFor class heeft een ‘GetMockFor<T>’ methode om een door SpecsFor geïnstantieerd Mock object in te stellen en uit te vragen. In onze bovengenoemde test methodes vragen we aan ons mock object of de ‘Add()’ en de ‘SaveChanges()’ methode op onze repository zijn aangeroepen.

Voor alle informatie en details omtrent het gebruik van Moq verwijs ik naar de documentatie van het Moq framework.

Als we bovenstaande testen nu laten draaien, dan zullen beide falen vanwege het ontbreken van een implementatie van onze ‘TeamsManager.Add()’ methode.

Om nu onze testen te laten slagen dienen we de Add() en SaveChanges() methodes op onze repository aan te roepen. Laten we onze methode eens voorzien van de volgende implementatie:

Als we nu onze test opnieuw uitvoeren dan zien we dat ze succesvol worden afgerond.

Laten we nu eens een methode aan onze TeamsManager class toevoegen om een Team uit te lezen uit onze repository en hiervoor een test te schrijven. We voegen hiervoor een nieuwe geneste van SpecsFor<TeamsManager> afgeleide test class toe aan onze specs class en in de overschreven When() methode roepen we de Get() methode van onze TeamsManager class aan en in onze ‘then’ testmethode testen we het resultaat van deze call:

Als we nu deze test uitvoeren dan zien we dat deze faalt:

De test faalt hier omdat de repository een null resultaat retourneert. Om dit te verhelpen, dienen we ook hier ons mock object in te stellen in the Given() methode. We dienen hier aan het Moq framework te vertellen, dat wanneer er een aanroep gedaan wordt naar de GetById() methode van de repository, er een Team instance dient te worden geretourneerd:

En nu slaagt onze test:

Tot zover een korte introductie van het BDD testframework ‘SpecsFor’.

Bronnen gebruikt voor dit artikel:

PluralSight (https://www.pluralsight.com/courses/automated-testing-aspdotnet-specsfor)

SpecsFor (http://specsfor.com/)

Moq (https://github.com/Moq/moq4/wiki/Quickstart)

(Auteur: Marcel Slegt © 2018 Bergler Competence Center)