top of page

Zoekresultaten

55 items gevonden voor ""

  • DevOps Performance Trends

    In de dynamische wereld van DevOps en performance engineering is het essentieel om op de hoogte te blijven van de laatste trends en ontwikkelingen. Hier zijn enkele inzichten en verwachtingen op dit gebied, met wat voorbeelden om elke trend te illustreren. Containerisatie binnen performance engineering De opkomst van containertechnologie heeft de wereld van performancetests radicaal veranderd. Door traditionele test- en productieomgevingen te vervangen met containers, biedt deze technologie tal van voordelen. Een van de grootste voordelen van containers is om omgevingen te klonen en testomgevingen op te zetten wanneer dat nodig is. Dit elimineert inconsistenties in omgevingen en draagt bij tot betrouwbare testresultaten. Containerisatie en microservices-architecturen zorgen vaak wel voor extra complexiteit. Door performancetests uit te voeren, is er meer inzicht in hoe deze services samenwerken en presteren onder verschillende belastingen en kunnen bottlenecks/inefficiënt resourcegebruik worden geïdentificeerd die anders verborgen zouden blijven. Dit vergroot de transparantie in deze complexe systemen en maakt het mogelijk om problemen proactief aan te pakken. De toekomst van containertechnologie belooft schaalbaarheid en automatisch herstel. Toekomstige tools zullen naar verwachting zelfherstellende en automatisch schaalbare containers mogelijk maken. Performancetests spelen een cruciale rol bij het valideren van deze functionaliteiten en het garanderen van een robuust systeem. De Rol van AI in Performancetests Artificial Intelligence (AI) zal naar verwachting een belangrijke rol gaan spelen in performanceengineering. AI kan helpen bij de analyse van testresultaten en bij het maken van voorspellingen en modellen. Huidige tools zijn voornamelijk gefocust op het genereren van belasting, maar AI kan voor de analyse van de resultaten verbeteren. Steeds meer Application Performance Monitoring (APM)-tools integreren AI om meer betekenisvolle grafieken te genereren voor het interpreteren van data. Shift-left Performancetesting Shift-left performancetesting, waarbij tests eerder in het ontwikkelingsproces worden uitgevoerd, wint aan terrein maar is nog niet wijdverspreid. Slechts ongeveer 4% van de bedrijven heeft dit succesvol geïmplementeerd, maar deze bedrijven zien wel goede resultaten. Bedrijven kunnen performancetests binnen de ontwikkelomgeving, zodat ontwikkelaars direct feedback krijgen op hun code. Daarnaast kunnen ze performancetests integreren in de build-pipeline om ervoor te zorgen dat nieuwe builds onmiddellijk worden getest op schaalbaarheid en performance. Introductie van DevPerfOps Een nieuw concept dat wordt geïntroduceerd is DevPerfOps, een combinatie van DevOps en performance engineering. Deze trend is geïnspireerd door de introductie van DevSecOps en streeft naar verbeterde softwareperformance gedurende de hele ontwikkelingscyclus. Door performancetests te integreren in elke fase van de DevOps-cyclus, van ontwikkeling tot productie, en CI/CD tools te gebruiken, kunnen bedrijven de softwareperformance aanzienlijk verbeteren. Monitoring en observability-tools (zoals Grafana en Prometheus) kunnen worden ingezet om realtime performancegegevens te verzamelen en te analyseren gedurende de gehele levenscyclus van de software. Veranderende Rol van Performance Engineers In cloud-native omgevingen verandert de rol van performance engineers. Het belang van uitgebreide kennis en expertise in dit vakgebied wordt benadrukt. Performance engineers moeten zich voortdurend aanpassen aan nieuwe technologieën en methodologieën om effectief te blijven. Dit kan onder andere door training en door samen te werken met ontwikkelteams om performancebewuste code te schrijven en de beste praktijken voor schaalbaarheid en efficiëntie te implementeren. Focus op Efficiëntie en Betrouwbaarheid Een belangrijk aandachtspunt binnen DevOps het waarborgen van betrouwbaarheid en efficiëntie. Vanwege de hoge kosten van cloudservices is er een nieuwe beweging ontstaan, genaamd FinOps, gericht op het beheersen en het verlagen van cloud-kosten. Onvoldoende geteste systemen brengen namelijk naast hogere risico's en ook vaak onbedoeld hoge kosten met zich mee. Met het opzetten van goede performancetests kan de efficiëntie van applicaties worden aangetoond. Zeker in combinatie met FinOps-tools zoals CloudHealth of Cloudability zijn performancetesten goed te gebruiken om cloudkosten te monitoren en te optimaliseren. Toekomstige Inzichten Met deze inzichten wordt duidelijk dat bedrijven die deze trends omarmen, hun efficiëntie en betrouwbaarheid aanzienlijk kunnen verbeteren. De integratie van AI, de focus op kostenbeheer via FinOps, en de adoptie van containerisatie en shift-left testing zijn cruciale ontwikkelingen voor de toekomst van DevOps en performance engineering.

  • Kennismiddag Prometheus en WireMock

    Onze maandelijkse kennismiddag was deze keer gevuld met twee onderwerpen, Prometheus en WireMock advanced. Prometheus zien we steeds vaker bij onze klanten gebruikt worden en daarom is dit een goed moment voor verbreding en verdieping van onze kennis van dit monitoring platform. WireMock is al eens eerder aan bod geweest op een kennismiddag en vandaag gingen we verder de diepte in, iets wat we graag doen bij PerformanceArchitecten. Beide onderwerpen zijn als korte workshop voorbereid zodat dit als groep efficiënt opgepakt en uitgewerkt konden worden. Prometheus is een open-source systeemmonitoring- en alerting platform dat oorspronkelijk werd ontwikkeld bij SoundCloud. Sinds de oprichting in 2012 hebben veel bedrijven en organisaties Prometheus omarmd. Het project heeft een actieve community van ontwikkelaars en gebruikers en wordt nu onafhankelijk onderhouden, los van enig bedrijf. In 2016 trad Prometheus toe tot de Cloud Native Computing Foundation als het tweede gehoste project, na Kubernetes. Het bekijken van een aantal video’s uit de playlist ‘Prometheus Monitoring with Julius’ op YouTube heeft ons snel op weg geholpen. Julius Volz is mede-oprichter van Prometheus en hij geeft in deze video’s op een heldere manier uitleg over Prometheus. Daarnaast bevat de website prometheus.io een flink aantal docs, blogs en tutorials. Daarna begon het hands-on gedeelte met installatie van Prometheus middels Docker. Na het verkennen van Prometheus hebben we ervaren hoe eenvoudig nieuwe ‘targets’ toegevoegd kunnen worden aan Prometheus en hebben we instrumentatie middels een sample applicatie in Go bekeken. We hebben het onderwerp Prometheus afgesloten met het maken van een Grafana dashboard waarin de metrics van datasource Prometheus zijn gebruikt. De kant en klare dashboards die geïmporteerd kunnen worden in Grafana zijn zeer handig en besparen je veel werk. In het kort onze bevindingen: het opzetten van een Prometheus instantie, vooral met Docker, is eenvoudig. Het implementeren van monitoring met Prometheus is ook relatief simpel. Het is een efficiënt hulpmiddel met een eenvoudige integratie met Grafana en een grote, actieve community. Echter, er zijn ook enkele nadelen. De grafieken van Prometheus zijn beperkt, dus je hebt snel Grafana of een ander hulpmiddel nodig. Het aanpassen van je eigen applicaties voor Prometheus monitoring lijkt in eerste instantie eenvoudig, maar kan al snel complex worden. Bovendien is er een steile leercurve door het gebruik van Promql.Conclusie: Prometheus biedt een eenvoudige en efficiënte oplossing voor monitoring, met sterke community-ondersteuning en naadloze integratie met Grafana, ondanks een steile leercurve en complexiteit. Het tweede onderwerp die middag was advanced WireMock . WireMock is een krachtige en flexibele open-source tool die is ontworpen voor API-mocking. WireMock stelt je in staat om mock-API’s te maken die echte scenario’s en API’s simuleren. Na kort onze WireMock kennis opgefrist te hebben zijn we met een WireMock docker container aan de gang gegaan. Na het bekijken van diverse mappings zijn we de WireMock admin API gaan gebruiken. Als opdracht hebben we met behulp van een JMeter script mappings aangemaakt en weer verwijderd. Op deze manier kan bijvoorbeeld het testen met mocks in een pipeline gerealiseerd worden. Verder hebben we WireMock cloud (hosted versie van WireMock ), libraries en templates bekeken. Onze bevindingen: WireMock is een gebruiksvriendelijke, open-source tool met handige functies zoals on-the-fly definitie creatie en kant-en-klare stubs via WireMock Templates. Echter, de functionaliteit is simpel (beperkt), de cloudversie kan kosten met zich meebrengen, en de documentatie en kwaliteit van de templates kunnen beter. Conclusie: ondanks enkele uitdagingen, biedt WireMock een gebruiksvriendelijke, veelzijdige en kosteneffectieve oplossing voor het simuleren van API’s. We hebben de dag afgesloten met een gezamenlijke maaltijd en kijken terug op een leuke en leerzame kennismiddag met Prometheus en WireMock waarin we in korte tijd heel veel geleerd hebben over dit monitoring platform en deze mocking tool.

  • Kennisdeling en Innovatie: de doelen van PerformanceArchitecten in 2024

    Bij PerformanceArchitecten vinden we het belangrijk om onze kennis en expertise met elkaar te delen. Daarom organiseren we maandelijks een kennismiddag. Tijdens deze middag verdiepen we ons in een bepaald onderwerp. Dit kan gaan over methoden, technieken, nieuwe of bijgewerkte tools en andere actuele onderwerpen die voor ons vakgebied interessant zijn. De eerste kennismiddag van het jaar is altijd een speciale dag. We kijken terug op het afgelopen jaar, bepalen samen waar we de focus op willen leggen in het komende jaar (dit noemen wij de rode draad) en stellen de doelen vast. Afgelopen dinsdag 23 januari hebben we onze kennismiddagenjaar geopend. We begonnen de dag met een M&M retrospective waarbij we op een leuke manier teruggekeken op het afgelopen jaar.  Daarna hebben we met een aantal brainstormsessies, met verschillende werkvormen, ideeën opgedaan en onze doelen opgesteld voor 2024. Uiteindelijk hebben we de volgende rode draad onderwerpen gekozen: AI als hulpmiddel bij ons werk SRE (Site Reliability Engineering) OpenShift / K8s kennis verbeteren Bijblijven met tools DevOps (hoe verandert dit en waarom ontstaan er varianten zoals DevSecOps en DevPerfOps) De kennismiddagen van PerformanceArchitecten zijn een belangrijke motor voor kennisontwikkeling en samenwerking. Ze zijn een moment om elkaar te ontmoeten, te leren van elkaar en samen te werken aan de ontwikkeling van onze vakgebieden. We zijn erg enthousiast over de onderwerpen die we voor het komende jaar hebben gekozen. We zijn ervan overtuigd dat ze ons zullen helpen om onze kennis en expertise verder te ontwikkelen. We zullen hierover ook een aantal blogs schrijven om onze kennis met anderen te delen.

  • Gatling simulaties in een executable jar

    In deze blog neem ik je mee in hoe ik bij mijn huidige opdracht een Gatling framework heb opgezet i.c.m. IntelliJ IDEA en Apache Maven en hoe ik uit dat framework met een simpel commando een executable fat jar kan produceren. Het voordeel van een dergelijke jar is dat je eigenlijk op elke server met java een Gatling simulatie kan uitvoeren zonder afhankelijk te zijn van een maven installatie of de aanwezigheid/bereikbaarheid van externe libraries. Het is een vrij technische handleiding die je hierbij kan helpen, zonder dat jezelf het wiel opnieuw hoeft uit te vinden. Ik ben hierbij vooral benieuwd naar jouw ervaringen. Zijn er wellicht nog slimmere manieren om dit te doen? Ik hoor het graag! Installatie Gatling (Using IntelliJ en Maven) Installeer java jdk. Via https://gatling.io/docs/current/installation#java-version kan je zien welke java versies Gatling ondersteund. Installeer Apache Maven. Installeer IntelliJ IDEA. Niet noodzakelijk, wel makkelijk. Deze blog gaat ervan uit dat IntelliJ IDEA geïnstalleerd is. De (gratis) Community editie is prima om mee te werken. Eventuele bijzonderheden m.b.t. de installatie kan je hier vinden: https://gatling.io/docs/current/installation#intellij-idea. Het is dus belangrijk om de Scala plugin te installeren. De code voor de Gatling performance testen zijn geschreven in Scala (https://www.scala-lang.org/). Nu zijn er meerdere opties om een Gatling framework op te zetten in IntelliJ. Je kan zelf een Maven project initiëren en de pom.xml aanpassen, maar ik vind het makkelijker om Gatling’s Maven Archetype te gebruiken. Op deze manier heb je ook meteen een structuur waarin je je resources en code kwijt kan en je hebt launchers voor de Recorder en de load test Engine. Hoe nu verder? Je kan nu via Recorder scripts maken. De ene mogelijkheid is om de Recorder te gebruiken als recorder (de Recorder is een proxy en vangt netwerk verkeer af). De andere optie is om de Recorder als HAR converter te gebruiken. Het resultaat is een script (simulation) die je kan draaien via maven commando’s of via de Engine. Het e.e.a. hierover kan je vinden op https://gatling.io/docs/current/quickstart. Maar deze blog gaat over het creëren van een executable fat jar. Wat is dat? Dit is een jar die alle gecompileerde code bevat, de resources EN de dependencies (external libraries). Dit maakt de jar ook een fat jar. Het voordeel hiervan is dat je op de server waarvandaan je de test wil draaien enkel java nodig hebt. Dus geen maven of een benaderbare repository met de dependencies (external libraries). En hoe maken we nu zo’n executable fat jar? Maken van executable fat jar Toevoegen scala-maven-plugin Wat je toe moet voegen aan de POM.xml voor de scala-maven-plugin kan je hier vinden: https://gatling.io/docs/current/installation#with-maven. Je hebt de scala-maven-plugin nodig om de scala code te compileren en toe te voegen aan de jar. Toevoegen maven-shade-plugin De maven-shade-plugin gebruiken we om de executable fat jar te bouwen. Het volgende moet je toevoegen aan de POM.xml: org.apache.maven.plugins maven-shade-plugin ${maven-shade-plugin.version} *:* META-INF/*.DSA META-INF/*.SF META-INF/*.RSA package shade io.gatling.app.Gatling Als mainClass is io.gatling.app.Gatling ingevuld. Dat betekent dus dat wanneer je de jar uitvoert dat de Gatling app wordt uitgevoerd. test → main De maven-shade-plugin stopt alleen de resources en code uit src/main in de package. Daarom moeten we de spullen in “test” verhuizen naar main (src/test à src/main). Let op! Hierdoor werken je Recorder en Engine en maven commando’s niet meer. Dit kan je wel weer werkend krijgen door in de POM.xml en IDEPathHelper.scala het e.e.a. aan te passen. In IDEPathHelper moet je overal “test” vervangen door “main” en bij mavenBinariesDirectory moet je “test-classes” vervangen door “classes”. In de POM.xml moet je bij de gatling-maven-plugin wat configuratie toe voegen: ${project.basedir}\src\main\scala ${project.basedir}\src\main\resources ${project.basedir}\src\main\resources Hoe executable fat jar uitvoeren? Je kan de jar uitvoeren door het volgende commando uit te voeren: java -jar -.jar -s Je kan dezelfde argumenten gebruiken als bij de bundle versie van Gatling: https://gatling.io/docs/current/general/configuration/?highlight=command%20line#command-line-options Hiermee kan je dus je Gatling simulatie uitvoeren op elke server (waarbij dus alleen java een vereiste is!). Dit kan bijvoorbeeld handig zijn als je niet afhankelijk wil zijn van een bepaalde server waarvandaan je je loadtesten uitvoert. Nawoord Ik hoop dat deze blog duidelijk was. Als er nog vragen zijn of op- of aanmerkingen dan hoor ik het graag! Er komen nog wat blogjes aan m.b.t. Gatling (“Gatling in de pipeline” en “Gatling output in Splunk”. Mocht je willen dat ik een specifiek aandachtspunt meeneem in die blog’s, laat het dan hier even weten, dan probeer ik daar rekening mee te houden. Bedankt voor jullie aandacht.

  • Ervaringen Performance.Now() 2019

    Afgelopen 21 en 22 november is de tweede Performance.Now() conferentie gehouden. Onze collega René Meijboom (RM) was erbij. Vanuit PerformanceArchitecten (PA) hebben wij hem kort wat vragen gesteld over zijn ervaringen. Benieuwd? Lees dan snel verder! Ha René. jij bent bij de Performance.Now() conferentie geweest. Wil jij in het kort vertellen wat de conferentie inhoudt? RM: Performance.Now() is een conferentie toegespitst op web performance cq FrontEnd performance. Het is een single track conferentie met een keur aan gerenommeerde sprekers op dit specifieke vakgebied. PA: Klinkt goed. Voor welk publiek is het in jouw ogen interessant? RM: FrontEnd performance is een onderwerp dat steeds belangrijker wordt omdat er steeds meer gebeurt en steeds meer mogelijk is in bijvoorbeeld de browser. Maar keuzes die hierbij gemaakt worden hebben vaak veel invloed op de performance van een website of applicatie. Dan kan het aan de achterkant nog zo goed geregeld zijn, maar heeft de eindgebruiker nog steeds geen goede gebruikerservaring. Dit kan dan weer resulteren in een lagere conversion rate of ontevreden klanten. Maar om even op je vraag terug te komen.. Ik denk dat het interessant is voor zowel ontwikkelaars als (performance) testers in organisaties waar een goede performance voor eindgebruikers key is. En dat zijn er heel veel.. PA: Dank, duidelijk denk ik. En wat heb jij met FrontEnd performance? RM: Bij mijn huidige klant (een grote Nederlandse bank, red) is een goede performance van webapplicaties van groot belang. Jaren geleden waren wij al bezig met ‘the last mile’ bijvoorbeeld. Hierbij keken we naar responstijden, hoeveel mensen er gelijktijdig kunnen werken en de perceptie van snelheid. Hierover heb ik ook eerder al geblogd. Zie: Frontend-performance-meting-als-aanvulling-op-de-traditionele-manier-van-performancetesten. Verder is het een onderwerp wat ik interessant vind, waarin ik me graag verdiep en wat volgens mij steeds belangrijker gaat worden. PA: Interessant, dank je wel. Kan je kort weergeven wat jou ervaringen waren? RM: Zeker, graag. Over het algemeen genomen waren de presentaties van goed niveau en er zijn veel aspecten aan bod gekomen. Henri Helvetica verzorgde de Keynote waarin hij de 14 regels voor snellere web sites van Steve Souders (auteur van “High Performance Web Sites”) opnieuw tegen het licht hield. In hoeverre houden zijn aanbevelingen van meer dan 10 jaar geleden nog stand. Een interessante keynote die duidelijk maakte dat ondanks dat de (web)wereld in 10 jaar flink veranderd is, een hoop regels nog steeds gelden. Het gaat te ver om alle sprekers afzonderlijk te benoemen, maar met name de presentaties van Tammy Everts (CEO SpeedCurve) over “the 7 Habits of Highly Effective Performance Teams” and Tim Kaldec (consultant) over “When JavaScript Bytes” spraken mij zeer aan. Zonder de overige sprekers te kort te doen, zijn ook de presentaties van Ilya Grigorik (Google), Harry Roberts (Consultant) en Stuart McMillan zeer de moeite van het terugkijken waard. PA: Top. Kunnen we de praatjes nog ergens terugvinden? RM: Ja, alle video´s en slides van de conferentie zijn terug te vinden op de website perfnow.nl. PA: Fijn. Goede tips. Verder nog take aways? RM: Wat mij opviel is dat er meer aandacht voor de conferentie leek te zijn vanuit ontwikkelaars dan vanuit de performance test hoek. Zeker goed om te zien dat er vanuit Dev dus blijkbaar veel aandacht is voor performance, maar ik denk dat het zeker ook goed en interessant is voor performance specialisten. PA: En, volgend jaar weer? RM: Ja, als het even kan zeker. En een tip voor iedereen: Als je dan toch op de website perfnow.nl  bent om de presentaties te bekijken, schrijf je dan gelijk in voor volgende jaar want het is zeer de moeite waard! PA: Super. Dank voor je tijd. Tot slot: woor iedereen die vragen heeft of gewoon wat meer weten wil, neem gerust contact op!

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

    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: @fast en @unit testen, maar niet de @wip normale testen zonder @fast, @unit, @slow of @wip tag. 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.

  • Veel gestelde vragen over SpecFlow

    Bij Performance Architecten hebben we de laatste tijd veel te doen met SpecFlow voor ontwikkeling volgens het Behaviour Driven Development proces. En als je eenmaal veel met een onderwerp bezig bent, kan je ook veel vragen verwachten van mensen die er ook mee bezig gaan. Zo krijg ik regelmatig dezelfde vragen die blijkbaar nog niet helemaal duidelijk zijn in de documentatie of waarvan de antwoorden niet zo 1-2-3 te vinden zijn op het internet. Daarom heb ik een FAQ opgesteld (Frequently Asked Questions oftewel Veel Gestelde Vragen) over de gebruikerskant van SpecFlow. Hoe kan ik een feature inactief maken? Gebruik de @ignore tag en features of scenarios worden automatisch overgeslagen Zijn er meer vooraf gedefinieerde tags? @wip wordt vaak gebruikt voor Work In Progress en zal als je het goed instelt overgeslagen worden tijdens een automatische run. @owner:Bas maakt automatisch een Microsoft.VisualStudio.TestTools.UnitTesting.OwnerAttribute aan. @workitem:123 maakt een Microsoft.VisualStudio.TestTools.UnitTesting.WorkItemAttribute aan voor de betreffende test of testen. Kan ik comments toevoegen aan mijn steps? Ja, in principe wordt alles wat je boven een background of scenario (wanneer er geen background is) toevoegt gezien als commentaar. In een scenario of examples tabel kan je commentaar toevoegen met het hekje: # Kan ik ook een blok commentariëren? Niet zoals je gewend bent in C# / Java etc met /* */. Je kan wel een stuk selecteren en met de Visual Studio shortcut CTRL+K,C te voorzien van comment hekjes en CTRL+K,U om snel te uncommenten. Je kan ook een stuk selecteren in “column mode” door de ALT in te houden en met je muiscursor een selectie te maken. Daarna tik je een hekje of haal je het weg om te uncommenten. Mijn testdata bevat pipes en die wil ik in een tabel kwijt. Hoe doe ik dat? Pipes kan je escapen met een backslash ervoor: | Pipe\|ndustries |. Dit zal nu gezien worden als 1 woord: Pipe|ndustries De code editor kan wat raar doen met highlighting, maar het werkt gewoon binnen je testen. Hoe krijg ik mijn output mooi vormgegeven voor de business? Je kan Pickles gebruiken, het maakt je feature files op in MarkDown format en kan ook de testresultaten koppelen. Je kan ook het output formaat kiezen: HTML, Word, Excel en meer. Waar vind ik een handleiding voor SpecFlow? – Op de site van SpecFlow zelf: http://www.specflow.org/ – Op de Cucumber site: https://cucumber.io/ – Het Cucumber boek: https://pragprog.com/book/hwcuc/the-cucumber-book Hoe kan ik ervoor zorgen dat er voor of na een feature of scenario een actie plaatsvindt? Maak gebruik van hooks zoals [BeforeScenario] of [AfterFeature]. Je kan ook tags instellen zodat bij [BeforeScenario(“web”)] en alleen bij het gebruik van de @web tag er een browser opgestart wordt voor een scenario. Kijk op de SpecFlow wiki hoe je het precies moet implementeren. Kan ik ook websites testen met SpecFlow? SpecFlow is alleen de runner. Je kan daar de functionaliteit aan koppelen die je maar wilt. Bijvoorbeeld de Selenium library voor .NET waarmee je websites kan testen. Kan ik step libraries herbruiken? Ja, maar de SpecFlow code generator (die testmethods maakt van je steps) moet wel weten waar die staan. Je moet een stepAssembly node toevoegen aan je app.config om de generator te laten weten welke libraries je wilt gebruiken: Kijk op de SpecFlow wiki voor meer technische details.

  • SpecFlow Extensies voor Dummies

    TechTalk heeft voor SpecFlow natuurlijk al een handige set aan extensies uitgebracht die vooral het gebruik van eigen datatypes in combinatie met SpecFlow steps mogelijk maken. Dit is slimme, maar vrij geavanceerde set waarbij je best wel wat ervaring moet hebben met zowel het gebruik van SpecFlow als C#. De beginnende gebruiker zal eerder behoefte hebben om SpecFlow tables in meer simpele maar generieke types om te zetten als collecties. Die methoden worden niet standaard geleverd in de SpecFlow library, waarschijnlijk omdat ze als triviaal gezien worden door het ontwikkel team. De .ToDictionary Extensie Een van de fijnste data collections in C# is natuurlijk de Dictionary. Een key/value collectie waarbij de key uniek is. Daarom is het fijn om een verticale SpecFlow.Table om te kunnen zetten in een Dictionary. Hiervoor gebruiken we een extension method. Hiervoor maken we eerst een extension class: Nu kunnen we onze eerste extension method aanmaken; een ToDictionary extension dat een SpecFlow Table omzet naar een dictionary: Deze methode neemt van iedere rij uit een verticale SpecFlow tabel de eerste twee kolommen. De eerste kolom worden de key, de tweede kolom de value van de dictionary. We hadden dit natuurlijk ook in een one-line Linq expressie kunnen doen, maar dat gaat het doel van simpel en begrijpelijk voorbij. Houdt er rekening mee dat als er foute waarden meegegeven worden, zoals een niet unieke key, de methode een standaard “An element with the same key already exists in the Dictionary.” exceptie gooit. Laten we hier een test voor schrijven om te controleren of het werkt: En we maken de drie steps aan die erbij horen. In deze steps gebruiken we de extensie Table.ToDictionary() methode, de extensie die we net hebben aangemaakt. Mocht dit in eerste instantie niet werken: vergeet niet de library met de extensies te importeren. Verder gebruiken we in deze drie steps het ScenarioContext.Current object om de Table en uiteindelijk de Dictionary door te geven tussen de steps. Het ScenarioContext.Current object is zelf ook een dictionary van het type , je kan er dus elke type object ingooien wat je maar wilt. Als je een object terug wilt halen moet je wel aangeven wat voor type het is, “casten”, om alle methodes en properties van dit object weer te gebruiken. Dit zie je hieronder gebeuren met behulp van het type tussen haakjes: var table = (Table)ScenarioContext.Current["table"] En natuurlijk de proef op de som, het runnen van de test: De .ToDataTable Extensie Een ander prettig datatype voor als je meer data hebt, is de DataTable. Vergelijkbaar met de Dictionary, maar dan twee dimensionaal in plaats van een dimensionaal. Hiervoor maken we een ToDataTable extensie op een vergelijkbare manier als we de ToDictionary extensie hebben gemaakt: Deze methode verblijft in de TableExtension class, want het is een extensie op het SpecFlow.Table object. Laten we er een test voor schrijven: We recyclen de Given step, maar voor de When en Then steps moeten we twee steps aanmaken: In deze steps gebruiken we zowel de Table.ToDictionary extensie als de nieuwe Table.ToDataTable extensie. In de Then step vergelijken we een Dictionary op overeenkomst met een DataTable.Row. Deze step gaat er wel vanuit dat de data welgevormd is. Als bijvoorbeeld een key uit de dictionary niet bestaat als column in de datatable krijg je een standaard exceptie toegeworpen. Laten we de test uitvoeren: Conclusie Soms is het handig als je een SpecFlow.Table object kan omzetten naar een meer C# eigen object. Twee voor de hand liggende object typen zijn de Dictionary en de DataTable. Met behulp van extensions kan je makkelijk het Table object uitbreiden om te converteren naar een object naar keuze. De code behorend bij deze exercitie vind je in blog: 'SpecFlow Extensies voor Dummies, de code'.

  • Automated Approval Testing with Dynamic Data Sets

    For some tests, you’ll need to check if files or documents are the same as they were before, or that they comply with a certain format. When something differs, you need to “reject” or “approve“ them, or even make them the new baseline if you are welcoming the changes. We call this Approval Testing. For more use cases, take a look at the nice presentation of Emily Bache about this subject with the catchy title Catching Dancing Ponies. A nice package that can help you with this is ApprovalTests. You can import it as a package and use it right away. Approval Testing is not only limited to text documents, this is a little example on how to use AppovalTests on a scraped webpage: [TestMethod] public void ApproveTheHomePageHTML() { Scraper scraper = new Scraper(@"https://qualityengineers.nl"); var html = scraper.GetHTML(); Approvals.VerifyHtml(html); } The first time this runs, it will make a snapshot of the text and save it to a file. The second time you run the test, it will look for differences and once there is one, your favorite diff or merge tool will open and you can approve the change or reject them and raise a bug. This way you can, for example, track that your homepage is unchanged and when it changes, the test will fail until you approve the changes. OK, but now the challenge we are facing: can we approve a dynamic amount of documents? How it is currently designed, I can only use one TestMethod for one approval test because the stored approved text gets the name of the method, like ApproveWebScrape.ApproveTheHomePageHTML.approved.html. So if I want to approve the contacts page too, I'll have to add another test. But when new pages are added (like this new blogpost today), I also want them to be added to the approved pages collection. And I want it dynamically because I am lazy. To dynamically get web content, we are embedding the webpage-scraper into a crawler. (Crawlers are using scrapers to collect all the links and will visit them until a whole domain is scraped. This is an example of a crawler: var crawler = new Crawler(@"https://qualityengineers.nl"); var folder = new DirectoryInfo(@"c:\temp\storedPages"); var filePath = crawler.Crawl(folder); Console.WriteLine($"{filePath.Count()} pages have been crawled."); This crawler enters a domain, and tries to follow all links in that domain and stores the pages it will find as text in the given folder. We can loop through all files in the folder and try to approve them, but it will only be in one method! That is against the design of atomic tests… We are going to use the following design: Get all pages from a domain using a crawler Store them in a folder as separate files Make a list of all stored files Inject each file into a data driven test Let’s start with a data driven test and assume we already scraped the files with the crawler above and stored a list with these files in a .csv file. [TestMethod] public void ApproveEverythingFromFolderCSVFile() { var fileToApprove = TestContext.DataRow<0>.ToString(); // get the next file to approve from the csv and approve it using (var file = new StreamReader(fileToApprove)) { var text = file.ReadToEnd(); Approvals.Verify(text); } } (You’ll need to have a public TestContext TestContext {get; set;} property in your class as well if you haven’t one already) But now, the file gets always verified against one verify file called something like ApproveWebScrape.ApproveEverythingFromFolderCSVFile.approved.html. resulting in lots of false positives (and consequentially an unworkable situation). To solve this, we are going to assign a custom name for each file to test with the Approvals.RegisterDefaultNamerCreation(Func creator) method. This looks a bit complicated if you never burned your finger onto lambda expressions or delegates, but an example will follow. All we need is a namer that implements the IApprovalNamer interface, so let’s do it: // implements our own namer class CustomNamer : IApprovalNamer { public CustomNamer(string sourcePath, string name) { SourcePath = sourcePath; Name = name; } public string Name { get; private set; } public string SourcePath { get; private set; } } Implementing an Interface is not very hard: Just type : ISomeInterface behind a new class definition and Visual Studio will automatically suggest to insert the missing members. You can do without a constructor, but this just looks better J. And now, use it in our Approve Everything method: [TestMethod] public void ApproveEverythingFromFolderCSVFile() { // get the filename that will also be used as unique id var fileToApprove = TestContext.DataRow<0>.ToString(); // register a name creator that makes a unique name for this compare/approval Approvals.RegisterDefaultNamerCreation(() => new CustomNamer(@"C:\temp\approved", Path.GetFileName(fileToApprove)) ); // get the next file to approve from the csv and approve it using (var file = new StreamReader(fileToApprove)) { var text = file.ReadToEnd(); Approvals.Verify(text); } } We are good to go, unless you want to have your data automatically collected just at the start of the test. We can use the attribute to gather the data and make the CSV file that will be used later on: [ClassInitialize] public void CrawlPagesAndPrepareDataSet() { Crawler crawler = new Crawler(@"https://qualityengineers.nl"); DirectoryInfo folder = new DirectoryInfo(@"c:\temp\storedPages"); List filePaths = crawler.Crawl(folder); using (StreamWriter file = new StreamWriter(@"C:\temp\files.csv")) { file.WriteLine("Dummy Header"); // csv files needs a header row foreach (string filePath in filePaths) file.WriteLine(filePath); } } Conclusion Approval Testing seems to be a useful way of testing in particular use cases. Especially if you want to compare and merge in a tool that is designed for that job. In this article, the focus is on one major drawback we experienced: not being able to test a dynamic amount of data. Fortunately, after researching the inner workings of the ApprovalTests framework, we discovered the ability to customize names, allowing us to dynamically assign approval data. With the use of the Data Driven Test capabilities of the standard Microsoft UnitTest framework, we could create a pattern on how to dynamically collect, verify and approve data.

  • Creëer meer eenheid in je SpecFlow steps met Step Argument Transformations

    Laatst kreeg ik de vraag, “Hoe maak je in je testdata onderscheid tussen een regular expression en een gewone tekst”. Oftewel: Hoe beheer je verschillende soorten steps als ze alleen verschillen in de manier waarop data vergeleken wordt. Je hebt een veld en je wilt controleren of er een bepaalde waarde in staat, maar soms ook of het matcht aan een pattern, of het een waarde bevat of misschien dat het een bepaalde minimum lengte heeft: # exact value Then the name field is equal to "Douglas Adams" # contains a value Then the name field contains "Adams" # matching a pattern Then the name field is matching the regex "+ +" # minimum field length Then the name field contains at least 2 characters Je zal nu geneigd zijn om 1 van de volgende oplossingen te kiezen: 1. Voor elk check-type maak je een aparte stepdefinitie aan. Dit levert in dit geval 4 verschillende steps op die marginaal verschillen in de Assert sectie. 2. Je maakt één step die alle verschillende gevallen aankan door middel van een switch of een if/else if boom. Beide zijn niet echt ideaal te noemen: Je zal het waarschijnlijk voor veel meer velden willen gaan inbouwen wat óf een wildgroei aan steps op gaat leveren, óf heel veel herhalende code in de vorm van switch statements. Ik ben al een tijd fan van Fluent Assertions, een library die je assertions in menselijke taal laat noteren. Wat nu als we dat gedrag kunnen nabootsen en daar een generiek component voor gaan schrijven: # exact value Then the name field should be "Douglas Adams" # contains a value Then the name field should contain "Adams" # matching a pattern Then the name field should match regex "+ +" # minimum field length Then the name field length should be greater or equal to "2" De gegenereerde code ziet er als volgt uit: [Then(@"the name field should be ""(.*)""")] public void ThenTheNameFieldShouldBe(string expectedValue) { ScenarioContext.Current.Pending(); } We kunnen de daadwerkelijk compare actie er nu uit halen en die voeden in een switch statement: [Then(@"the name field (.+) ""(.*)""")] public void ThenTheNameFieldShouldBe(string compareAction, string expectedValue) { // normally the actual value is retrieved from your application var actualValue = "Douglas Adams"; switch (compareAction) { case "should be": actualValue.Should().Be(expectedValue); break; case "should contain": actualValue.Should().Contain(expectedValue); break; case "should match regex": actualValue.Should().MatchRegex(expectedValue); break; case "length should be greater or equal to": actualValue.Length.Should().BeGreaterOrEqualTo(Convert.ToInt32(expectedValue)); break; default: throw new ArgumentException("Compare action is not a valid action"); } } Dit levert nog geen reusable code op, maar je ziet wellicht waar dit heen gaat: we kunnen dit deel ook weer generiek maken. Dat doen we door een step argument transformatie. Hiervoor zetten we een class in de argumentenlijst, SpecFlow zal nu proberen dit te converteren naar dit object met behulp van een zogenaamde StepArgumentTransfomation: [Then(@"the name field (.+) ""(.*)""")] public void ThenTheNameFieldShouldBeComparable(ShouldComparer compareAction, string expectedValue) { // normally the actual value is retrieved from your application var actualValue = "Douglas Adams"; // ShouldComparer action here... } De ShouldComparer moet gevoed worden met de actie die het moet uitvoeren en bij een call naar een Execute method de daadwerkelijke actie ook uitvoeren: public class ShouldComparer { private readonly Action _action; public ShouldComparer(Action action) { this._action = action; } public void Execute(T1 actual, T1 expected) => _action(actual, expected); } Als het T1 type je wat verward: In dit geval maken we gebruik van Generics. De T1 staat voor het type waarmee de class wordt aangemaakt, zodat we niet alleen de actie op string types uit kunnen voeren, maar op elk type dat wordt ondersteund door Fluent Assertions. In ons geval maken we een ShouldComparer aan voor strings (dat wordt gedaan door definitie ShouldComparer compareAction in de stepmethod parameters), maar zo kunnen we de ShouldComparer later ook voor andere object typen gebruiken. Nu volgt de implementatie: we moeten SpecFlow vertellen hoe het een string zoals “should be” of “should match regex” moet ombouwen naar de juiste actie. Hiervoor maken we een nieuwe StepArgumentTransformation methode aan die in een public class met een binding attribute moet staan. De methode moet een parameter ontvangen van het type waarvan we willen converteren en een object teruggeven van het type waarnaar we willen converteren. [Binding] public class ShouldTransformations { public ShouldComparer shouldTransformationWithTypedComparer(string term) { switch (term) { case "should be": return new ShouldComparer((actual, expected) => actual.Should().Be(expected)); case "should contain": return new ShouldComparer((actual, expected) => actual.Should().Contain(expected)); case "should match regex": return new ShouldComparer((actual, expected) => actual.Should().MatchRegex(expected)); case "should be greater or equal to": return new ShouldComparer((actual, expected) => actual.Length.Should().BeGreaterOrEqualTo(Convert.ToInt32(expected))); default: throw new ArgumentException("the term was not recognized"); } } } In dit geval staan hier alleen de vier gevallen die in het scenario staat aangegeven, maar in de praktijk zal je hier alle gevallen zetten die je (potentieel) wilt gebruiken zoals Should().NotBe() of Should().Match(). Nu hoeven we alleen nog de Execute method aan te roepen in de stepdefinitie: [Then(@"the name field (.+) ""(.*)""")] public void ThenTheNameFieldShouldBeComparable(ShouldComparer compareAction, string expectedValue) { var actualValue = "Douglas Adams"; compareAction.Execute(actualValue, expectedValue); } Bij nieuwe steps hoef je in je stepdefinitie alleen nog maar een ShouldComparer toe te voegen en je hebt alle functionaliteit die je al eerder hebt geïmplementeerd voor een compare. Als je andere en/of eigen objecten wilt comparen, dan kan dat ook. Je kan je eigen StepArgumentTransformation schrijven voor elk type dat je wilt comparen, of je gebruikt de generieke implementatie: [StepArgumentTransformation] public ShouldComparer ShouldTransformationWithTypedComparer(string term) { switch (term) { case "should be": return new ShouldComparer((actual, expected) => actual.Should().Be(expected)); case "should not be": return new ShouldComparer((actual, expected) => actual.Should().NotBe(expected)); default: throw new ArgumentException("the term was not recognized"); } } Deze comparer kan je feeden met elke willekeurige class en de Fluent Assertions library zal automatisch een compare maken. De CompareAction class kan je eventueel ook nog fluent maken zodat er een nog beter leesbaar statement uit voortkomt: compare.Actual(actualValue).With().Expected(expectedValue); Conclusie: In bepaalde SpecFlow steps wil je vaak meer testen dan alleen gelijkheid van data. Het inbouwen van een mechanisme om ook te vergelijken op bijvoorbeeld ongelijkheid, het matchen op een pattern of een minimum veldlengte kan resulteren in een wildgroei aan steps of het opblazen van de step methodes met veel herhaling. Door gebruik te maken van Fluent Assertions en Step Argument Transformations hebben we een generiek bruikbaar patroon die de vergelijkingsactie lostrekt van de overige acties in de glue code. Hiermee maken we onze code meer DRY en verkrijgen we een hogere mate van Separation of Concerns.

  • Regular Expressions en Testautomatisering, twee problemen of juist een oplossing?

    Bij geautomatiseerde checks wil je regelmatig een verwachte waarde controleren tegen een actuele waarde. Vroeg of laat kom je dan in aanraking met wildcards: Je wilt bijvoorbeeld weten of de tekst “Er zijn 42 resultaten gevonden” voorkomt, maar het aantal, hier 42, kan variabel zijn. Van 42 wil je dan een wildcard maken. De meest gebruikte wildcard language is de regular expression. Binnen het testautomatiseren gebruik ik graag regular expressions: De basis is universeel over alle programmeertalen. Er zijn vele (online) regular expression testers verkrijgbaar Er bestaat heel veel documentatie over Je kan anderen (collega’s/fora) eenvoudig om hulp vragen Maar eigenlijk is de belangrijkste reden: Je kan de definitie scheiden van de implementatie Wat betekent dit? Je hoeft de check niet programmatisch af te handelen. Laten we kijken hoe we dit programmatisch zouden kunnen afhandelen: public void CheckCorrectResultAmountMessage(string actualText) { // Check the start of the text Assert.IsTrue(actualText.StartsWith("Er zijn ")); // Check the end of the text Assert.IsTrue(actualText.EndsWith(" resultaten gevonden")); // Grab the amount var amountText = actualText.Replace("Er zijn ", "").Replace(" resultaten gevonden", ""); // Check if the amount is a valid integer int amount; Assert.IsTrue(int.TryParse(amountText, out amount), "The amount '{0}' is not a valid integer", amountText); } Dat is best wel veel gedoe voor de check van 1 regel tekst en dan zijn er nog genoeg cases die niet afgedekt worden: negatieve waarden worden niet als foutief gezien, wat gebeurt er als je ‘4 2’, ‘4.2’, ‘4e2’ of ‘4,2’ terugkrijgt? (dit vereist interne kennis over de int.TryParse method). En hoe ga je dit uitbreiden naar “Er zijn geen resultaten gevonden” en “Er is 1 resultaat gevonden”? Het onderliggende probleem is: We proberen twee problemen tegelijkertijd op te lossen: Wat we willen checken en hoe we dat doen. Een betere strategie is om dat uit elkaar te trekken. We kunnen dit oplossen door een regular expression te gebruiken: public void CheckCorrectResultAmountMessage(string actualText) { var pattern = "^Er zijn <0-9>+ resultaten gevonden$"; Assert.IsTrue(Regex.IsMatch(actualText, pattern)); } Nu kunnen de definitie (wat) en de implementatie (hoe) scheiden waarbij je het pattern op een andere plek bepaalt (in een config file, een database, Excel bestand of je testscenario) dan waar je het test. Als we dit bijvoorbeeld in een Feature file gebruiken dan bepalen we in de feature file de definitie (Wat we testen): Scenario: There must be an amount displayed if there are results Given I search for "ipod" Then I can see the message "Er (zijn \d+ resultaten|is 1 resultaat) gevonden" Scenario: A message should be shown when no results are found Given I search for "sony walkman" Then I can see the message "Er zijn geen resultaten gevonden" en in de step definitie de implementatie (Hoe we dat doen): [Then(@"I can see the message ""(.*)""")] public void ThenICanSeeTheMessage(string expectedMessagePattern) { var msg = MyFancyWebApp.GetMessage(); Assert.IsTrue(Regex.IsMatch(msg, expectedMessagePattern)); } Regular expressions is maar één gebied dat je helpt om definitie en implementatie te scheiden. Binnen applicatie development en dus ook test automatisering is Separation of Concerns een leidend principe dat je binnen een goede code basis veel terug zal zien komen. Samen met DRY (Don't Repeat Yourself) en KISS (Keep It Simple Stupid) vormt dit de basis code principes waarmee je niet alleen jezelf, maar ook je team enorm helpt.

  • SSL/TLS versie en cipher in OpenText LoadRunner

    In deze blog wil ik even stilstaan bij de resultaten van een performance test die niet overeenkwamen met de verwachtingen die wij als team hadden. Een aantal transacties gingen in responstijd omhoog en het CPU gebruik nam flink toe. Omdat het ons veel tijd heeft gekost, deel ik dit graag met jullie zodat wij performance testers hier in de toekomst kostbare tijd mee kunnen besparen! Uiteindelijk zagen we dat bij de SSL/TLS handshake een verkeerde cipher werd gebruikt. Daarom beschrijf ik onderstaand hoe je er achter komt welke SSL/TLS versie en cipher je moet instellen in VuGen en hoe je dit dan doet. Wat is SSL/TLS? SSL staat voor Secure Sockets Layer en is een encryptie-protocol die de communicatie tussen computers beveiligd. Vaak wordt de term SSL gebruikt terwijl SSL veelal is vervangen door TLS (Transport Layer Security). Het opzetten van een verbinding met een andere computer gebeurt volgens de volgende stappen: Uitwisselen publieke sleutels, vergelijken ondersteunde SSL/TLS versies en afspreken versleutelmechanisme (cipher). Op basis van uitgewisselde publieke sleutels wordt een gezamenlijke sleutel (session key) bepaald m.b.v. het Diffie-Hellman-mechanisme. De uitwisseling van data vindt nu plaats gebaseerd op de afgesproken cipher en de session key. Waarom zorgde het gebruik van de verkeerde cipher voor hogere responstijden en CPU toename? De ene cipher is de andere niet. In productie wordt een zogenaamde NULL-cipher gebruikt. Oftewel, het verkeer wordt niet versleuteld. In mijn performance test gebruikte LoadRunner de default cipher ECDHE-RSA. In dit geval wordt het verkeer dus wel versleuteld en dit was dan ook de oorzaak van de hogere responstijden en CPU gebruik. Hoe kom je nu achter de juiste SSL version en cipher? Dit is een beetje afhankelijk van de situatie. Wordt de applicatie benaderd via een browser of via een andere applicatie? In het geval van een applicatie die benaderd wordt via de browser, kan je de openssl tool gebruiken. Deze is beschikbaar in de bin folder van je loadrunner installatie: Virtual User Generator\bin of LoadRunner\bin. Door de applicatie te runnen, kom je in een command prompt. Hier typ je het commando: In de output zal dan iets staan als: Als we het nu hebben over een applicatie die benaderd wordt door een andere applicatie, moet de SSL versie en cipher op een andere manier achterhaald worden. Dit kan bijvoorbeeld door de beheerders hiernaar te vragen of door in de (productie) logging te (laten) kijken van de web server die de applicatie bedient. Op mijn opdracht wordt Apache gebruikt en daar worden SSL protocol en cipher gelogd in de access log. In de log pattern is dit gedefinieerd als %{SSL_PROTOCOL} en %{SSL_CIPHER}. Voorbeeld: 1.1.1.1 - - SUCCESS TLSv1.1 ECDHE-RSA-AES256-SHA "POST /ta/ HTTP/1.1" 200 En hoe stel je de SSL_VERSION en SSL_CIPHER nu in? In VuGen kan je SSL version en cipher instellen via de functie web_set_sockets_option. SSL version kan ook ingesteld worden via Runtime Settings (Internet Protocol > Preferences > General > SSL version). De cipher kan hier niet ingesteld worden. Als ik de gegevens overneem van de voorbeelden, moeten de volgende regels toegevoegd worden aan het VuGen script: web_set_sockets_option("SSL_VERSION", "TLS1.1"); web_set_sockets_option("SSL_CIPHER_LIST", "ECDHE-RSA-AES256-SHA"); Let wel op het volgende: de oplettende lezer heeft vast al gezien dat de waarde voor SSL_VERSION niet helemaal overeenkomt met de voorbeelden. Er staat namelijk TLS1.1 i.p.v. TLSv1.1. In de Vugen Function Reference kan je de toegestane waardes terugvinden. De toegestane waardes voor SSL_CIPHER_LIST is niet beperkt. De waarde NULL-MD5 staat bijvoorbeeld (nog) niet in deze lijst, maar wordt wel geaccepteerd en heeft ook effect bij het runnen van het script. Ik ben heel benieuwd of dit iets is wat jezelf ook wel eens hebt meegemaakt. Ook lees ik graag of je weleens soortgelijke uitdagingen hebt gehad. Ik hoor dus graag van je😉!

bottom of page