top of page
Foto van schrijverBas Dam

MSTest, SpecFlow, de Command Line en het gebruik van Category Parameters

Bijgewerkt op: 9 nov 2023


De titel is een hele mond vol, maar laat het me uitleggen. Ik was op zoek hoe je aan kan geven welke testen je wilt uitvoeren met MSTest. Ik kon wel wat simpele voorbeelden vinden, maar hoe je wat complexere logica toevoegt heb ik zelf moeten uitvogelen en dat wil ik graag delen. De eerste twee paragrafen zijn voor de context, hoe je MSTest vanaf de command line uitvoert en hoe je SpecFlow reports aanmaakt vanuit een test result file is niet nieuw.


Uitvoer vanaf de Command Line


Voor het dagelijks runnen van onze SpecFlow testen gebruiken we MSTest. Wellicht is NUnit een betere keuze, maar in dit geval is MSTest de testrunner die voortkomt uit de preferred way of working binnen onze afdeling en dat is weer handig als er een collega van een ander scrum team met onze solution aan de slag gaat: Hij hoeft zich niet eerst in te lezen in NUnit, maar kan meteen met de tool aan de slag die hij kent.


Als je MSTest correct configureert produceert het een zogenaamde .trx (Test Results Xml) file. MSTest voor Visual Stdio 2012 vind je op het path C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MSTest.exe, dus als je deze folder toevoegt aan je PATHs, dan kan je MSTest starten vanaf een willekeurige positie op de command line. We openen een command prompt. Ik ga er nu voor het gemak vanuit dat de command prompt op de locatie van de project file staat.


De .trx file maak je aan door een resultsfile mee te geven:

MSTest.exe /testcontainer:\bin\debug\glibglob.dll

/resultsfile:\TestResults\results.trx

Let op dat de results file niet al bestaat, want dan krijg je een error.


Aanmaken van een SpecFlow rapport


De results file kan je gebruiken om een mooi SpecFlow rapport aan te maken met specflow.exe dat meekomt met de installatie van de package:

specflow.exe mstestexecutionreport glibglob.csproj

/testresult:\TestResults\results.trx /out:\TestResults\GlibGlob.html


Met mstestexecutionreport geven we aan dat het om een results file gaat dat uit MSTest komt, je kan ook instellen dat het bijvoorbeeld uit NUnit komt met nunitexecutionreport.

De testresult parameter geeft aan waar de test resultaten gevonden kunnen worden.

En de out parameter geeft aan hoe het rapport heet dat gegenereerd wordt.


Bepalen welke testen uitgevoerd worden


Met MSTest kan je bepalen welke testen uitgevoerd moeten worden. Dat kan met de /category:[..] optie. MSTest kijkt tijdens runtime naar de TestCategory attributen van de TestMethods in je project.


Het leuke is dat je in SpecFlow tags kan meegeven en deze tags vertalen zich 1 op 1 met de TestCategoryattributen. Zo kan je dus met de /category:[..] optie bepalen welke tags er in- of uitgesloten worden van je test.


En hier komt het onduidelijke deel: hoe werkt het als je meerdere tags wilt insluiten en meerdere wilt uitsluiten. Zo hebben we @unit, @fast, normale (geen tag) en @slow testen, en ook een @wip (work in progress) tag.

Microsoft geeft aan dat je met behulp van | (or), & (and) en ! (not) dit kan aansturen en deze operators ook kan combineren (behalve & en |).


In onze usecase willen we drie testen achter elkaar uitvoeren zodat we drie progressieve feedback loops krijgen:

  1. @fast en @unit testen, maar niet de @wip

  2. normale testen zonder @fast, @unit, @slow of @wip tag.

  3. En uiteindelijk de @slow testen, maar niet de @wip


Als we een prototype maken in een feature file, dan ziet dat er als volgt uit:

Feature: MSTest Tags Test
In order to get feedback at the right time
As a test automation specialist
I want to categorize my tests and run them accordingly

@slow
Scenario: A test tagged unit
Given 'twas brillig
When gyre and gimble in the wabe
Then all mimsy were the borogoves

@slow @wip
Scenario: A test tagged unit but wipped
Given a Jabberwocky with eyes of flame
When whiffling through the tulgey wood
Then burbled as it came

# [..] en alle varianten

Op deze manier verkrijgen we de volgende 10 testen:

Naam Tags

ATestTaggedFast @fast

ATestTaggedUnit @unit

ATestTaggedFastButWipped @fast, @wip

ATestTaggedOther @other

ATestTaggedOtherButWipped @other, @wip

ATestTaggedSlow @slow

ATestTaggedSlowButWipped @slow, @wip

ATestTaggedUnitButWipped @unit, @wip

ATestWithoutTags

ATestWithoutTagsButWipped @wip


Als we alle testen zouden uitvoeren dat zien we het volgende:

Loading CategoryTest.dll...

Starting execution...


Results Top Level Tests

------- ---------------

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedFast

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedFastButWipped

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedOther

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedOtherButWipped

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedSlow

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedSlowButWipped

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedUnit

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedUnitButWipped

Inconclusive CategoryTest.TagsTestFeature.ATestWithoutTags

Inconclusive CategoryTest.TagsTestFeature.ATestWithoutTagsButWipped


0/10 test(s) Passed, 10 Inconclusive


We hebben nog geen step definities gemaakt, dus alle testen zijn inconclusive. Dat is voor het voorbeeld niet belangrijk.


Om alleen de testen uit te voeren met de @slow tag, maar niet met de @wip tag is redelijk eenvoudig:


MSTest.exe /testcontainer:CategoryTest.dll /category:"slow&!wip"

Loading CategoryTest.dll...

Starting execution...


Results Top Level Tests

------- ---------------

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedSlow


0/1 test(s) Passed, 1 Inconclusive


Om alle testen uit te voeren die niet in de slow, fast, unit en wip categorie vallen sluiten we ze allemaal uit met de volgende setting:


MSTest.exe /testcontainer:CategoryTest.dll /category: "!slow&!fast&!unit&!wip"

Loading CategoryTest.dll...

Starting execution...


Results Top Level Tests

------- ---------------

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedOther

Inconclusive CategoryTest.TagsTestFeature.ATestWithoutTags


0/2 test(s) Passed, 2 Inconclusive


En dan is het ook eenvoudig om alleen de @unit en @fast testen uit te voeren terwijl alle @wip testen uitgesloten worden. Toch? Tijd om te testen:


Laten we starten met het meest voor de hand liggende setting, unit of fast, maar niet wip:


MSTest.exe /testcontainer:CategoryTest.dll /category:"unit|fast&!wip"

TestCategory filter "unit|fast&!wip" is invalid. The "&" and "|" operators cannot be used together in a test category filter.


Hmm, dat is waar ook, je kan geen AND en OR filter tegelijkertijd instellen:


“The test category filter consists of one or more test category names separated by the logical operators ‘&’, ‘|’, ‘!’, ‘&!’. The logical operators ‘&’ and ‘|’ cannot be used together to create a test category filter.”


Alleen OR dan? Klinkt niet heel logisch maar makkelijk te testen:


MSTest.exe /testcontainer:CategoryTest.dll /category:"unit|fast|!wip"

Loading CategoryTest.dll...

Starting execution...


Results Top Level Tests

------- ---------------

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedFast

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedFastButWipped

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedOther

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedSlow

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedUnit

Inconclusive CategoryTest.TagsTestFeature.ATestTaggedUnitButWipped

Inconclusive CategoryTest.TagsTestFeature.ATestWithoutTags


0/7 test(s) Passed, 7 Inconclusive


Nee, dat zijn veel teveel testen: Er worden wips, others en slows getest en zelfs testen zonder tag.


En wat gebeurt er als we AND gebruiken?


MSTest.exe /testcontainer:CategoryTest.dll /category:"unit&fast&!wip"


Loading CategoryTest.dll...

Starting execution...

No tests to execute.


Logisch, want nu zoekt MsTest alleen de testen op die zowel de tag unit en fast hebben, maar niet wip.


Conclusie: Het is blijkbaar niet mogelijk om twee groepen in te sluiten en tegelijkertijd één of meerdere uit te sluiten. Het is dus belangrijk om secuur met je tags om te gaan door:

  • óf je gebruikt maar 1 tag voor een type test. Als je @fast gebruikt voor snelle testen, dan zal je alle @unitgetagde tests ook van de @fast tag moeten voorzien. Op die manier kan je een test uitvoeren met “fast&!wip”

  • óf je voorziet een test pas van een bepaalde tag als het niet meer een @wip tag heeft. Dan kan je het uitvoeren met “fast&unit”

Zelf zou ik voor de eerste optie kiezen: Op deze manier is het eenvoudiger om een test uit te sluiten als je hem tijdelijk uit de testset wilt halen.

5 weergaven0 opmerkingen

Recente blogposts

Alles weergeven

testRigor

Comentários


bottom of page