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://performancearchitecten.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://performancearchitecten.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://performancearchitecten.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

Impact tooling op performance: Dynatrace

21/09/2018

In deze blog geef ik kort de resultaten weer van een onderzoekje dat ik bij één van mijn laatste opdrachten heb gedaan naar de impact van het gebruik van de tool Dynatrace op de infrastructuur waar het op draait. Mocht je gebruik maken van tooling als Dynatrace of op een andere manier geïnteresseerd zijn in […]

Tips en tricks voor Protractor

06/09/2018

Vanuit PerformanceArchitecten doen we graag aan kennisdeling. Van tool reviews tot aan complete best practices maar ook van een aantal simpele tips en tricks die je kan gebruiken in je dagelijkse werk. Vandaag in die laatste categorie voor gebruikers van Protractor: (Javascript) timing issues en het managen van de volgorde van uitvoeren van actions. Inleiding […]

PerformanceArchitecten @The Next Web conferentie

04/07/2018

Was het een interessante conferentie? Beslist. Heeft TNW PerformanceArchitecten op nieuwe ideeën gebracht? Zeker. Heb jij TNW gemist, maar wil je je wel in vijf minuten op de hoogte laten brengen? Lees dan snel verder! En mocht je er wel zijn geweest.. We zijn benieuwd naar jouw beeld! Wat is de Next Web? Voor hen […]

De ‘waar begin ik met testautomatisering’ handleiding.

11/04/2018

Wij worden regelmatig gevraagd te helpen bij het opzetten of verbeteren van testautomatisering in een Agile omgeving bij een klant. En hoeveel ervaring je ook hebt, wat je opdracht ook precies inhoudt en in welk team je ook terechtkomt, het is altijd even zoeken waar te beginnen. Onderstaand stappenplan ondersteunt hierbij. PerformanceArchitecten organiseert veel kennissessies. Zo […]

Wat is het Bug Filter?

26/03/2018

Een algemeen gedeelde opvatting over het doel van testen binnen software ontwikkeling is “het tegenhouden van bugs en het afdekken van risico’s”. Over hoe dit vervolgens het best valt te organiseren, bestaan er echter vaak veel meningsverschillen. In deze 2 minute snack sta ik graag even stil bij een inzicht dat verhelderend werkt in deze […]

Testen? Begin bij de basis! | Het belang van unittesten

19/02/2018

Inleiding Mijn vrouw en ik zijn op dit moment bezig met het bouwen van een huis. In dit geval niet als bouwvakker of aannemer, maar dan toch wel als opdrachtgever. Spannend vinden we het zeker, leuk ook. Wat heeft dit te maken met unittesten zou je denken. Nou, het volgende… Het huis wordt namelijk gebouwd […]

De Absolute Beginners Guide voor API Testen met rest-assured.io

16/01/2018

Omdat het moeilijk was om een eenvoudige tutorial te vinden voor rest-assured.io, ben ik na eerst zelf uit te vinden hoe het werkt, maar eens begonnen met een tutorial die de absolute basics uitlegt over rest-assured. In deze post laat ik zien hoe we op een zo eenvoudig mogelijke manier een API test kunnen maken met […]

APACHE MPM (op *nix servers)

07/11/2017

Benieuwd naar de impact van het wijzigen van Apache MPM Prefork naar Worker? Lees dan door! Bij één van onze klanten heb ik dit onderzocht. Omdat dit ook interessant kan zijn voor anderen, deel ik mijn resultaten en ervaringen graag. Het is misschien wat technisch allemaal, maar voor performancetesters, de doelgroep, is het vast goed […]

Performancetesten en CI/CD, gaat dat samen?

13/10/2017

De afgelopen najaarseditie van Testnet stond onder het thema Continuous Everything vooral stil bij CI/CD en natuurlijk testen. Gezien DevOps en CI/CD ook grote invloed hebben op het vakgebied performance (testen), zijn wij blij dat we vanuit PerformanceArchitecten een bijdrage mochten leveren door middel van het delen van onze visie hierop. Onze collega René Meijboom […]

Een eerste indruk van Gauge

08/09/2017

Tijdens één van onze kennismiddagen hebben we gekeken naar het testtool Gauge. Doel van de sessie was om een beeld te krijgen wat de toegevoegde waarde van Gauge is voor een tester. Benieuwd naar onze ervaringen? Lees dan snel verder! Gauge is een open source project, gesponsord door ThoughtWorks en belooft in het kort het […]

Test Automation Framework BDD

16/06/2017

De afgelopen tijd heb ik in een opdracht collega’s mogen adviseren over de positieve impact van het Test Automation Framework BDD rondom het thema Agile. In een vorige blog ‘Transformation’ is te lezen wat BDD voor mij betekent en hoe BDD voor synergie zorgt tussen verschillende disciplines binnen Agile-teams met als doel het leveren van kwalitatief hoogwaardig […]

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

11/04/2017

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 […]