TestAutomatisering & PerformanceTesten

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:

  1. Get all pages from a domain using a crawler
  2. Store them in a folder as separate files
  3. Make a list of all stored files
  4. 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]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", @"c:\temp\files.csv", "files#csv", DataAccessMethod.Sequential)]
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<IApprovalNamer> 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]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", @"c:\temp\files.csv", "files#csv", DataAccessMethod.Sequential)]
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 [ClassInitialize] 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<string> 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.

Dit bericht is geplaatst in Testautomatisering en getagd in Approval Testing Test Automation

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Nieuws

Blijf op de hoogte

TNW 2023

26/06/2023

Het Next Web (TNW) Conference is een jaarlijks evenement dat professionals uit de wereld van technologie, innovatie en ondernemerschap samenbrengt. Dit jaar vond TNW 2023 plaats in Amsterdam (eigenlijk Zaandam). Ik kreeg de kans om aanwezig te zijn en wil graag mijn ervaringen delen in deze blogpost. Het centrale thema van dit tweedaagse evenement was […]

06/06/2023

Work hard, play hard! Dat laatste hebben we vrijdag 2 juni letterlijk genomen. We zijn naar een museum geweest, het Nationaal Videogame Museum in het stadshart van Zoetermeer. Voor gamefanaten is dit echt een feestje. We kregen een interessante rondleiding waarbij we van alles te weten kwamen over de ontwikkeling van videogames, vanaf de vroege […]

testRigor

17/05/2023

Zijn we klaar voor AI-gestuurde testautomatiseringstools? Een blik op testRigor. Bij PerformanceArchitecten vinden we het belangrijk om continu onze kennis te ontwikkelen en bij te houden. Daarom organiseren we elke maand een kennismiddag waarbij we ons verdiepen in verschillende onderwerpen die relevant zijn voor ons werk. Onze laatste kennismiddag stond in het teken van testRigor. […]

SRE – Site Reliability Engineering

19/04/2023

Tijdens de laatste maandelijkse kennismiddag van PerformanceArchitecten hebben we ons verdiept in het onderwerp SRE (Site Reliability Engineering). SRE combineert software engineering en operationele principes om grootschalige en complexe systemen te bouwen en beheren.   Ter introductie hebben we verschillende video’s bekeken waarin de definitie van SRE werd gegeven en het verschil tussen SRE en […]

NeoLoad RealBrowser

02/04/2023

Bij PerformanceArchitecten vinden we het belangrijk om continu onze kennis te ontwikkelen en bij te houden. Daarom organiseren we elke maand een kennismiddag, waarbij we ons verdiepen in verschillende onderwerpen die relevant zijn voor ons werk. Onze laatste kennismiddag stond in het teken van het RealBrowser “protocol” binnen het performancetesttool NeoLoad van Tricentis. Voor degenen […]

JMeter en Groovy

06/03/2023

Als je binnen JMeter iets wilt doen wat niet standaard in de tool zit, gebruik je plugins of ga je zelf code schrijven. In het geval dat je zelf code gaat schrijven, wordt aangeraden de groovy functie en JSR223 sampler te gebruiken. Ik wil hieronder graag bespreken welke mogelijkheden deze 2 opties je bieden, maar […]

Kennismiddag: ChatGPT

19/02/2023

Tijdens de maandelijkse kennismiddag op 14 februari bespraken collega’s de ontwikkelingen rondom ChatGPT, een tool die AI gegenereerde resultaten kan opleveren. Het werd onderzocht of ChatGPT ondersteuning kon bieden bij SEO en scripting. Hoewel de tool potentieel heeft, is verdere input en domeinkennis nog steeds nodig. ChatGPT is geen perfecte oplossing, maar kan wel handig zijn bij de uitvoering van werk. Het was een geslaagde middag en er wordt uitgekeken naar nieuwe onderwerpen voor de volgende kennismiddag.

16/09/2022

Performancetesten overdragen naar teams We zien bij onze klanten een duidelijke verschuiving van verantwoordelijkheden van centrale teams naar DevOps teams. “You build it, you run it” zorgt ervoor dat teams niet alleen zelf software moeten bouwen, testen en in productie brengen, maar ook verantwoordelijk zijn voor hoe de applicatie in productie draait. Eén van de […]

Azure Bicep

09/12/2021

Introductie Binnen de Azure omgeving is er veel mogelijk zoals bijvoorbeeld het runnen van pipelines en het creëren van infrastructuur. Maar om van deze mogelijkheden gebruik te kunnen maken zijn er uiteraard resources nodig. Deze resources zijn manueel via de portal aan te maken, maar ook door gebruik te maken van ARM (Azure Resource Manager) […]

Azure DevOps pipeline performance quality gate

31/10/2021

In mijn vorige blogs heb ik geschreven over Gatling simulaties in een executable jar en Azure DevOps pipeline met gatling. In het laatste blog had ik al aangegeven dat ik de performancetest onderdeel wilde laten zijn van de CD pipeline door het toevoegen van quality gates. Oftewel, ik wil dat de resultaten van de performance […]

Introductie in Pytest

07/04/2021

Inleiding Voor mijn huidige project ben ik bezig met het aspect kwaliteit in combinatie met Big Data. In zo’n modern project wordt hierbij ook AI gebruikt. Het inrichten van AI wordt vaak niet gedaan door ontwikkelaars, maar door data scientists die een omgeving nodig hebben wat het AI werk kan doen. De programmeertaal Python is […]

Website performance, belangrijker dan je denkt

27/11/2020

Inleiding We kennen het allemaal: je bent aan het surfen om iets te kopen. Duurt het langer dan 1 à 2 seconden dan haak je al snel af. Desondanks is performance is vaak onderbelicht in web-ontwikkeling. De nadruk ligt vaak op functionaliteit en minder op performance. Dat terwijl een slechte performance behoorlijke impact heeft op […]