I hope you at least heard of the concept of Unit Testing as it is one of the principal pillars of software development. Its purpose is to automatically check the functionality of isolated components of your code, but it adds a lot of benefits:

  • your code becomes more modular - you only worry about the code you change
  • your code becomes more readable - clear dependency chain and tests demonstrate in code what was the purpose of particular features
  • you gain confidence that your code works as you are making changes to it - refactoring without unit tests in place is usually dangerous
  • changing any component with another implementation does not affect the overall application

This post is a companion to the Programming a simple game in pure HTML and Javascript in the sense that it is that game that we will be testing. Also, as per the requirements of that project, we will not be using any of the numerous unit testing frameworks available for Javascript code.

When we left off the development of the game we had three files:

  • complementary.html - the structure of the page
  • complementary.css - the visual design of the page components
  • complementary.js - all the code of the game, including the initialization and the game starting bit

In order to test our individual components, we need to separate them. So let's split complementary.js in four files:

  • complementary.js - just the game start (instantiating Game and initializing it)
  • game.js - the Game class
  • color.js - the Color class
  • elements.js - the custom HTML elements and their registration

Obviously the HTML will change to load all of these Javascript files. When we get to modules, this will become a non issue.

There are things that we could test on the custom HTML elements, but let's leave that aside. Also the two lines in complementary.js will not need testing. The simplest component should be the first to be tested and that is Color.

We start by creating a new HTML file (color tests.html) and we fill it with code that checks the Color class works as expected. First the code and then the discussion:

<html>

<head>
    <script src="color.js"></script>
    <script>
        // this can easily be changed to display a nice report in this page
        const assert ={
            true:(value, message)=> {
                if (value) {
                    console.log('Test PASSED ('+message+')');
                } else {
                    console.warn('Test FAILED');
                    alert(message);
                    throw new Error(message);
                }
            }
        };
    </script>
</head>

<body>
    <script>
        // Arrange
        const color1 = new Color(123);
        const color2 = new Color(123);
        const color3 = new Color(234);
        // Act
        const equalsWorks = color1.equals(color2);
        const notEqualsWorks = !color1.equals(color3);
        // Assert
        assert.true(equalsWorks,'Expected two colors initialized with the same value to be equal');
        assert.true(notEqualsWorks,'Expected two colors initialized with different values not to be equal');
    </script>

    <script>
        // Arrange
        const color = new Color();
        const doubleInvertedColor = color.complement().complement();
        // Act
        const complementAndEqualsWork = color.equals(doubleInvertedColor);
        // Assert
        assert.true(complementAndEqualsWork,'Expected the complementary or a complementary color to be the original color');
    </script>

    <script>
        // Arrange
        const acolor = new Color(0x6789AB);
        const stringColor = acolor.toString();
        // Act
        const toStringWorks = stringColor==='#6789ab';
        // Assert
        assert.true(toStringWorks,'Expected the HTML representation of the color to be #6789ab and it was '+stringColor);
    </script>

</body>

</html>

A test should follow the AAA structure:

  • Arrange - sets up the necessary items for the test to run
    • instantiate classes to be tested
    • mock functionality of dependencies - we will see this when we test Game
  • Act - executes the code intended to be tested and acquires results
  • Assert - verifies that the test results are the ones expected

Normally, a framework would take tests written in a certain way and then produce some sort of report, with nice green and red rows, with messages, with information on where errors occurred and so on. However, I intend to demonstrate the basics of unit testing, so no framework is actually needed.

A unit test:

  • is a piece of code (who unit tests the unit test?!)
  • it requires effort, it is just as prone to bugs as normal code and requires maintenance just like any other code (shit doesn't just happen, it takes time and effort)
  • it requires infrastructure that uses it to periodically test your changes (either someone does it manually or there is some setup to run it automatically and display/email the report)

In the code above I created a script tag for each test in which I am following AAA to create Color instances and then check their functionality does what it should. A very basic assert object is handling the reporting part. It remains homework for the reader to update that part or to plug in an existing unit testing framework.

The Color class is very simple:

  • it supports initializing with a color integer representing the RGB values of the color
  • toString method that returns the HTML representation of the color
  • complement method returns the complement of the color
  • equals method checks if two colors are equal

There are no external dependencies, meaning that it needs nothing from the outside in order to work. Game, for example, requires Color, which is a dependency for Game.

Open the color tests.html file in the browser and open the development tools (F12 or Ctrl-Shift-I) and refresh the page. You should see in the console that all the tests passed. Change something in a test so it fails and it should both throw an error in the console and show you a dialog with the failing test.

Now, let's test Game. The code of the game tests.html file:

<html>

<head>
    <script src="game.js"></script>
    <script>
        // this can easily be changed to display a nice report in this page
        const assert ={
            true:(value, message)=> {
                if (value) {
                    console.log('Test PASSED ('+message+')');
                } else {
                    console.warn('Test FAILED');
                    alert(message);
                    throw new Error(message);
                }
            }
        };
    </script>
</head>

<body>
    <script>
        // Arrange
        const game = new Game();
        // Act
        // Assert
    </script>

</body>

</html>

I used the same structure, the same assert object, only I loaded game.js instead of color.js. Then I wrote a test in which I do nothing than instantiate a Game. If you execute this page it will work just fine. No errors because we have not, in fact, executed anything. We need to execute .init(document), remember?

And now it becomes apparent why I chose to initialize the document from init instead of using window.document in my code. window.document is now the document of the test page, it has no complementary-board element in it. We haven't even defined any custom HTML elements or a Color class. In fact, we can now test that calling init with no parameter will fail:

    <script>
        // Arrange
        const game = new Game();
        // Act
        let anyError = null;
        try {
            game.init();
        } catch(error) {
            anyError = error;
        }
        // Assert
        assert.true(anyError!=null,'Expected the init method of a Game class to fail if run with no parameters ('+anyError+')');
    </script>

And, indeed, if we open the page now we get a console log like this: 

Test PASSED (Expected the init method of a Game class to fail if run with no parameters (TypeError: Cannot read property 'addEventListener' of undefined))

You just learned another important characteristic of a unit test: it tests both what should work and what shouldn't. This is one of the reasons why unit testing is hard. For each piece of code you need to test when it works and when it fails as expected. Now we have to test how Game should work, and that means we get into mocking.

Mocking is when you replace a dependency with something that looks exactly the same, but does something else. For unit tests mock objects need to do the simplest things and those things must be predictable.

Let's see how one of these tests would look:

    <script>
        // Arrange
        const mockDoc = {
            addEventListener:function() {
            }
        };
        const game2 = new Game();
        // Act
        let anyError2 = null;
        try {
            game2.init(mockDoc);
        } catch(error) {
            anyError2 = error;
        }
        // Assert
        assert.true(anyError2==null,'Expected the init method of a Game class to not fail if run with correct parameters ('+anyError2+')');
    </script>

Just by providing an object with an addEventListener function, the initialization of the game now works. mockDoc is a mocked document and this is called mocking.

Let's look at how would a "happy path" test look, one that assumes everything goes correctly and moves through and entire flow:

    <script>
        // Arrange
        const mockDoc3 = {
            testData : {},
            addEventListener:function(eventName,eventHandler) {
                this.testData.eventName = eventName;
                this.onLoad = eventHandler;
            },
            getElementsByTagName:function(tagName) {
                this.testData.tagName = tagName;
                return [this.mockBoard];
            },
            mockBoard: {
                setChoiceHandler:function(handler) {
                    this.choiceHandler=handler;
                }
            }
        };
        const game3 = new Game();
        // Act
        let anyError3 = null;
        try {
            game3.init(mockDoc3);
        } catch(error) {
            anyError3 = error;
        }
        Math = {
            random:function() {
                return 0.4;    
            },
            floor:function(x) { return x; },
            round:function(x) { return x; },
            pow:function(x,p) { if (p==1) return x; else throw new Error('Expected 1 as the exponent, not '+p); }
        };
        Color = {
            index:0,
            new:function(value) {
                return {
                    val: value,
                    equals: function(x) { return x.val==this.val; },
                    complement: function() { return Color.new(1000-this.val); }
                };
            },
            random:function() {
                this.index++;
                return Color.new(this.index*10);
            }
        }
        mockDoc3.onLoad();
        mockDoc3.mockBoard.choiceHandler(3);
        // Assert
        assert.true(anyError3==null,'Expected the init method of a Game class to not fail if run with correct parameters ('+anyError3+')');
        assert.true(mockDoc3.testData.eventName==='DOMContentLoaded','DOMContentLoaded was not handled!');
        assert.true(mockDoc3.testData.tagName==='complementary-board','Game is not looking for a complementary-board element');
        assert.true(game3._roundData.guideColor.val === 10,'Guide color object expected to have val=10 ('+JSON.stringify(game3._roundData.guideColor)+')');
        assert.true(game3._roundData.tries.size === 1,'Expected 1 unsuccessful try ('+JSON.stringify(game3._roundData.tries)+')');
        assert.true(game3._roundData.tries.has(3),'Expected unsuccessful try with value of 3 ('+JSON.stringify(game3._roundData.tries)+')');
        assert.true(game3._log.length === 0,'Expected no score after one unsuccessful try ('+JSON.stringify(game3._log)+')');
        // Act 2 (heh!)
        mockDoc3.mockBoard.choiceHandler(2);
        // Assert 2
        assert.true(game3._roundData.guideColor.val === 60,'Guide color object expected to have val=60 ('+JSON.stringify(game3._roundData.guideColor)+')');
        assert.true(game3._roundData.tries.size === 0,'Expected no unsuccessful tries after correct response ('+JSON.stringify(game3._roundData.tries)+')');
        assert.true(game3._log.length === 1,'Expected one item of score after correct answer ('+JSON.stringify(game3._log)+')');
        assert.true(game3._log[0] === 50,'Expected 50 as the score after one fail and one correct answer ('+JSON.stringify(game3._log)+')');
        
    </script>

There is a lot to unpack here, including the lazy parts of the test. Here are some of the issues with it:

  • it doesn't follow the AAA pattern, it asserts, then acts again, then asserts again
    • while this works, it doesn't encapsulate testing of a single feature
    • it is the equivalent of the classes or methods with multiple responsibilities from normal code
    • the correct way to do it is to write another test, have two choiceHandler calls in the Act part and assert only that particular path
  • it tests internal functionality
    • in order to write the test I had to look at how the Game class works internally and then tailor the test so it works
    • it accesses private data like _log and _roundData
  • the Game class did not abstract all of its dependencies
    • this is painfully obvious when mocking the Math object - in Javascript this is easy, but in other languages the Math functionality comes as an interface (a declaration of available members with no implementation)
    • this is not a test problem, but a Game problem which makes testing tedious
  • test contains logic
    • look at the Math and Color mocks, how they compute values and return objects
  • some values there are particularly chosen to "work"
    • have you noticed how random returns 0.4 so that multiplied with 5 (number of choices) it returns 2, which then is equal with the correct choice?
  • test is not independent
    • Math and Color are replaced with some static objects, thus changing the environment for following tests

But it works, even if it's not very well written. Here are some of its good features:

  • it tests a full game round with one bad and one good choice
  • it doesn't try to go around randomness by adding more code in the assertion part
    • it could have easily gone that way in order to determine the correct color in a random list, thus replicating or reverse engineering the Game logic into the test
  • all the expected results are completely predictable (the score values, the indexes, etc)
  • it tests only Game functionality, not others
    • I could have not mocked Color, loading color.js and thus relying in a single test on functionality from a dependency

The lessons learned from this tell us that both the Game code and the test code could have been written better in regard to maintainability, with dependencies clearly declared, easy to mock or replace. In fact, the greatest gain of a company with hiring a senior developer is not on how well code works, but how much time is saved and how much risk is avoided when the code is written with separation of concerns and unit testing in mind.

It is funny, but when a piece of code is not testable, writing a single unit test forces you to refactor it into a good shape. The rest of the tests only test functionality, as the class has been rewritten with testing in mind. So that is my advice: whenever you write something, even a silly game like Complementary, write one "happy path" unit test per class.

Homework for you: rewrite the Game class and its test class so that testing becomes easier and more correct.

and has 0 comments

This is a side post to Programming a simple game in pure HTML and Javascript in the sense that we are going to add that project to source control in GitHub using Visual Studio Code.

The first step is to create a repository. You need to create a GitHub account first, then either go to Your Repositories

or click the green New button on the top of your repositories list in the main page.

Make sure you give the repository a name and a decent description. I recommend adding a README and a licence (I use MIT), too.

Now that you have a remote repo on GitHub, you need to remember its URL, you will need it later.

Then download Git from their website. The Windows installer is simple to find, download and Next-next-next to success.

Open Visual Studio Code in your project's folder. On the left side menu there are a bunch of vertical buttons, click on the Source Control one 

Then initialize your local repository by clicking on the plus sign and selecting your project folder: 

Now you need to connect your local repo to your remote repo and you do this by typing some stuff in the Visual Studio Code Terminal window:

  1. set the remote by typing git remote add origin <your GitHub repo URL>
  2. verify the remote by typing git remote -v
  3. run a git pull to make sure your project loads the readme and license file by typing git pull origin master

Last step is to push your local files to the remote repository. You do this by

  1. clicking on the check mark at the top of the Source Control window and giving a description to this first commit

  2. pushing/publishing the commit, by clicking on the ... mark and choosing Publish Branch

There you have it. Your project is on source control.

You do this in order to not lose your changes, in order to track your changes forwards and backwards in time and to publish your work for others to see it (like other devs or potential employers)

Verify that all went well by refreshing your GitHub project page. The files in your local folder should now be visible in the file list on the page.

Now, every time you make changes to your code you push the changes on GitHub by committing (the check mark) and then pushing/syncing/publishing (from the ... menu)

The code for this series of posts can be found at https://github.com/Siderite/Complementary

  I was helping a friend with basic programming and I realized that I've been so caught up with the newest fads and development techniques that I've forgotten about simple programming, for fun, with just the base principles and tools provided "out of the box". This post will demonstrate me messing up writing a game using HTML and Javascript only.

Mise en place

This French phrase is used in professional cooking to represent the preparation of ingredients and utensils before starting the actual cooking. We will need this before starting developing our game:

  • description: the game will show a color and the player must choose from a selection of other colors the one that is complementary
    • two colors are complementary if when they are mixed, they cancel each other out, resulting in a grayscale "color" like white, black or some shade of gray. Wait! Was that the metaphor in Fifty Shades of Grey?
  • technological stack: HTML, Javascript, CSS
    • flavor of Javascript: ECMAScript 2015 (also known as ES6)
    • using modules: no - this would be nice, but modules obey CORS, so you won't be able to run it with the browser from the local file system.
    • unit testing: yes, but we have to do it as simply as possible (no external libraries)
  • development IDE: Visual Studio Code
    • it's free and if you don't like it, you can just use Notepad to the same result
  • source control: Git (on GitHub)

Installing Visual Studio Code

Installing VS Code is just as simple as downloading the installer and running it.

Then, select the Open Folder option, create a project folder (let's call it Complementary), then click on Select Folder.

The vanilla installation will help you with syntax highlighting, code completion, code formatting.

Project structure

For starters we will need the following files:

  • complementary.html - the actual page that will be open by the browser
  • complementary.js - the Javascript code
  • complementary.css - the CSS stylesheet

Other files will be added afterwards, but this is the most basic separation of concerns: code and data in the .js file, structure in .html and presentation in .css.

Starting to code

First, let's link the three files together by writing the simplest HTML structure:

<html>
    <head>
        <link rel="stylesheet" href="complementary.css"/>
        <script src="complementary.js"></script>
    </head>
    <body>
        
    </body>
</html>

This instructs the browser to load the CSS and JS files. 

In the Javascript file we encapsulate out logic into a Game class:

"use strict";
class Game {
  init(doc) {
    this._document = doc;
    this._document.addEventListener('DOMContentLoaded',this.onLoad.bind(this),false);
  }
  onLoad() {

  }
}

const game=new Game();
game.init(document);

We declared a class (a new concept in Javascript ES6) and a method called init that receives a doc. The idea here is that when the script is loaded, a new Game will be created and the initialization function will receive the current document so it can interact with the user interface. We used the DOMContentLoaded event to call onLoad only when the page document object model (DOM) has been completely loaded, otherwise the script would run before the elements have been loaded.

Also, not the use of the bind method on a function. addEventListener expects a function as the event handler. If we only specify this.onLoad, it will run the function, but with the this context of the event, which would be window, not our game object. this.onLoad.bind(this), on the other hand, is a function that will be executed in the context of our game.

Now, let's consider how we want to game to play out:

  • a guide color must be shown
    • this means the color needs to be generated
  • a list of colors to choose from must be displayed
    • colors need to be generated
    • one color needs to be complementary to the guide color
    • color elements need to respond to mouse clicks
  • a result must be computed from the chosen color
    • the outcome of the user choice must be displayed
    • the score will need to be calculated

This gives us the structure of the game user interface. Let's add:

  • a guide element
  • a choice list element
  • a score element
<html>
    <head>
        <link rel="stylesheet" href="complementary.css"/>
        <script type="module" src="complementary.js"></script>
    </head>
    <body>
        <div id="guideColor"></div>
        <div id="choiceColors"></div>
        <div id="score"></div>
    </body>
</html>

Note that we don't need to choose how they look (that's the CSS) or what they do (that's the JS).

This is a top-down approach, starting from user expectations and then filling in more and more details until it all works out.

Let's write the logic of the game. I won't discuss that too much, because it's pretty obvious and this post is about structure and development, not the game itself.

"use strict";
class Game {
    constructor() {
        // how many color choices to have
        this._numberOfChoices = 5;
        // the list of user scores
        this._log = [];
    }
    init(doc) {
        this._document = doc;
        this._document.addEventListener('DOMContentLoaded', this.onLoad.bind(this), false);
    }
    onLoad() {
        this._guide = this._document.getElementById('guideColor');
        this._choices = this._document.getElementById('choiceColors');
        // one click event on the parent, but event.target contains the exact element that was clicked
        this._choices.addEventListener('click', this.onChoiceClick.bind(this), false);
        this._score = this._document.getElementById('score');
        this.startRound();
    }
    startRound() {
        // all game logic works with numeric data
        const guideColor = this.randomColor();
        this._roundData = {
            guideColor: guideColor,
            choiceColors: this.generateChoices(guideColor),
            tries: new Set()
        };
        // only this method transforms the data into visuals
        this.refreshUI();
    }
    randomColor() {
        return Math.round(Math.random() * 0xFFFFFF);
    }
    generateChoices(guideColor) {
        const complementaryColor = 0xFFFFFF - guideColor;
        const index = Math.floor(Math.random() * this._numberOfChoices);
        const choices = [];
        for (let i = 0; i < this._numberOfChoices; i++) {
            choices.push(i == index
                ? complementaryColor
                : this.randomColor());
        }
        return choices;
    }
    refreshUI() {
        this._guide.style.backgroundColor = '#' + this._roundData.guideColor.toString(16).padStart(6, '0');
        while (this._choices.firstChild) {
            this._choices.removeChild(this._choices.firstChild);
        }
        for (let i = 0; i < this._roundData.choiceColors.length; i++) {
            const color = this._roundData.choiceColors[i];
            const elem = this._document.createElement('span');
            elem.style.backgroundColor = '#' + color.toString(16).padStart(6, '0');
            elem.setAttribute('data-index', i);
            this._choices.appendChild(elem);
        }
        while (this._score.firstChild) {
            this._score.removeChild(this._score.firstChild);
        }
        const threshold = 50;
        for (let i = this._log.length - 1; i >= 0; i--) {
            const value = this._log[i];
            const elem = this._document.createElement('span');

            elem.className = value >= threshold
                ? 'good'
                : 'bad';
            elem.innerText = value;
            this._score.appendChild(elem);
        }
    }
    onChoiceClick(ev) {
        const elem = ev.target;
        const index = elem.getAttribute('data-index');
        // just a regular expression test that the attribute value is actually a number
        if (!/^\d+$/.test(index)) {
            return;
        }
        const result = this.score(+index);
        elem.setAttribute('data-result', result);
    }
    score(index) {
        const expectedColor = 0xFFFFFF - this._roundData.guideColor;
        const isCorrect = this._roundData.choiceColors[index] == expectedColor;
        if (!isCorrect) {
            this._roundData.tries.add(index);
        }
        if (isCorrect || this._roundData.tries.size >= this._numberOfChoices - 1) {
            const score = 1 / Math.pow(2, this._roundData.tries.size);
            this._log.push(Math.round(100 * score));
            this.startRound();
        }
        return isCorrect;
    }
}

const game = new Game();
game.init(document);

This works, but it has several problems, including having too many responsibilities (display, logic, handling clicks, generating color strings from numbers, etc).

And while we have the logic and the structure, the display leaves a lot to be desired. Let's fix this first (I am terrible with design, so I will just dump the result here and it will be a homework for the reader to improve on the visuals).

First, I will add a new div to contain the three others. I could work directly with body, but it would be ugly:

<html>

<head>
    <link rel="stylesheet" href="complementary.css" />
    <script src="complementary.js"></script>
</head>

<body>
    <div class="board">
        <div id="guideColor"></div>
        <div id="choiceColors"></div>
        <div id="score"></div>
    </div>
</body>

</html>

Then, let's fill in the CSS:

body {
    width: 100vw;
    height: 100vh;
    margin: 0;
}
.board {
    width:100%;
    height:100%;
    display: grid;
    grid-template-columns: 50% 50%;
    grid-template-rows: min-content auto;
}
#score {
    grid-column-start: 1;
    grid-column-end: 3;
    grid-row: 1;
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
}
#score span {
    display: inline-block;
    padding: 1rem;
    border-radius: 0.5rem;
    background-color: darkgray;
    margin-left: 2px;
}
#score span.good {
    background-color: darkgreen;
}
#score span.bad {
    background-color: red;
}
#guideColor {
    grid-column: 1;
    grid-row: 2;
}
#choiceColors {
    grid-column: 2;
    grid-row: 2;
    display: flex;
    flex-direction: column;
}
#choiceColors span {
    flex-grow: 1;
    cursor: pointer;
}
#choiceColors span[data-result=false] {
    opacity: 0.3;
}

I used a lot of flex and grid to display things.

The game should now do the following:

  • displays a left side color
  • displays five rows of different colors in the right side
  • clicking on any of them modifies the score (each wrong choice halves the maximum score of 100)
  • when there are no more moves left or the correct choice is clicked, the score is added to a list at the top of the board
  • the score tiles are either green (score>=50) or red

However, I am dissatisfied with the Javascript code. If Game has too many responsibilities it is a sign that new classes need to be created.

Refactoring the code

First, I will encapsulate all color logic into a Color class.

class Color {
    constructor(value = 0  /* black */) {
        this._value = value;
    }
    toString() {
        return '#' + this._value.toString(16).padStart(6, '0');
    }
    complement() {
        return new Color(0xFFFFFF - this._value);
    }
    equals(anotherColor) {
        return this._value === anotherColor._value;
    }
    static random() {
        return new Color(Math.round(Math.random() * 0xFFFFFF));
    }
}

This simplifies the Game class like this:

class Game {
    constructor() {
        // how many color choices to have
        this._numberOfChoices = 5;
        // the list of user scores
        this._log = [];
    }
    init(doc) {
        this._document = doc;
        this._document.addEventListener('DOMContentLoaded', this.onLoad.bind(this), false);
    }
    onLoad() {
        this._guide = this._document.getElementById('guideColor');
        this._choices = this._document.getElementById('choiceColors');
        // one click event on the parent, but event.target contains the exact element that was clicked
        this._choices.addEventListener('click', this.onChoiceClick.bind(this), false);
        this._score = this._document.getElementById('score');
        this.startRound();
    }
    startRound() {
        // all game logic works with numeric data
        const guideColor = Color.random();
        this._roundData = {
            guideColor: guideColor,
            choiceColors: this.generateChoices(guideColor),
            tries: new Set()
        };
        // only this method transforms the data into visuals
        this.refreshUI();
    }
    generateChoices(guideColor) {
        const complementaryColor = guideColor.complement();
        const index = Math.floor(Math.random() * this._numberOfChoices);
        const choices = [];
        for (let i = 0; i < this._numberOfChoices; i++) {
            choices.push(i == index
                ? complementaryColor
                : Color.random());
        }
        return choices;
    }
    refreshUI() {
        this._guide.style.backgroundColor = this._roundData.guideColor.toString();
        while (this._choices.firstChild) {
            this._choices.removeChild(this._choices.firstChild);
        }
        for (let i = 0; i < this._roundData.choiceColors.length; i++) {
            const color = this._roundData.choiceColors[i];
            const elem = this._document.createElement('span');
            elem.style.backgroundColor = color.toString();
            elem.setAttribute('data-index', i);
            this._choices.appendChild(elem);
        }
        while (this._score.firstChild) {
            this._score.removeChild(this._score.firstChild);
        }
        const threshold = 50;
        for (let i = this._log.length - 1; i >= 0; i--) {
            const value = this._log[i];
            const elem = this._document.createElement('span');

            elem.className = value >= threshold
                ? 'good'
                : 'bad';
            elem.innerText = value;
            this._score.appendChild(elem);
        }
    }
    onChoiceClick(ev) {
        const elem = ev.target;
        const index = elem.getAttribute('data-index');
        // just a regular expression test that the attribute value is actually a number
        if (!/^\d+$/.test(index)) {
            return;
        }
        const result = this.score(+index);
        elem.setAttribute('data-result', result);
    }
    score(index) {
        const expectedColor = this._roundData.guideColor.complement();
        const isCorrect = this._roundData.choiceColors[index].equals(expectedColor);
        if (!isCorrect) {
            this._roundData.tries.add(index);
        }
        if (isCorrect || this._roundData.tries.size >= this._numberOfChoices - 1) {
            const score = 1 / Math.pow(2, this._roundData.tries.size);
            this._log.push(Math.round(100 * score));
            this.startRound();
        }
        return isCorrect;
    }
}

But it's still not enough. Game is still doing a lot of UI stuff. Can we fix that? Yes, with custom HTML elements!

Here is the code. It looks verbose, but what it does is completely encapsulate UI logic into UI elements:

class GuideColor extends HTMLElement {
    set color(value) {
        this.style.backgroundColor = value.toString();
    }
}

class ChoiceColors extends HTMLElement {
    connectedCallback() {
        this._clickHandler = this.onChoiceClick.bind(this);
        this.addEventListener('click', this._clickHandler, false);
    }
    disconnectedCallback() {
        this.removeEventListener('click', this._clickHandler, false);
    }
    onChoiceClick(ev) {
        const elem = ev.target;
        if (!(elem instanceof ChoiceColor)) {
            return;
        }
        const result = this._choiceHandler(elem.choiceIndex);
        elem.choiceResult = result;
    }
    setChoiceHandler(handler) {
        this._choiceHandler = handler;
    }
    set colors(value) {
        while (this.firstChild) {
            this.removeChild(this.firstChild);
        }
        for (let i = 0; i < value.length; i++) {
            const color = value[i];
            const elem = new ChoiceColor(color, i);
            this.appendChild(elem);
        }
    }
}

class ChoiceColor extends HTMLElement {
    constructor(color, index) {
        super();
        this.color = color;
        this.choiceIndex = index;
    }
    get choiceIndex() {
        return +this.getAttribute('data-index');
    }
    set choiceIndex(value) {
        this.setAttribute('data-index', value);
    }
    set choiceResult(value) {
        this.setAttribute('data-result', value);
    }
    set color(value) {
        this.style.backgroundColor = value.toString();
    }
}

class Scores extends HTMLElement {
    set scores(log) {
        while (this.firstChild) {
            this.removeChild(this.firstChild);
        }
        for (let i = log.length - 1; i >= 0; i--) {
            const value = log[i];
            const elem = new Score(value);
            this.appendChild(elem);
        }
    }
}

class Score extends HTMLElement {
    constructor(value) {
        super();
        this.innerText = value;
        this.className = value > 50
            ? 'good'
            : 'bad';
    }
}

class Board extends HTMLElement {
    constructor() {
        super();
        this._guide = new GuideColor();
        this._choices = new ChoiceColors();
        this._score = new Scores();
    }
    connectedCallback() {
        this.appendChild(this._guide);
        this.appendChild(this._choices);
        this.appendChild(this._score);
    }
    setChoiceHandler(handler) {
        this._choices.setChoiceHandler(handler);
    }
    set guideColor(value) {
        this._guide.color = value;
    }
    set choiceColors(value) {
        this._choices.colors = value;
    }
    set scores(value) {
        this._score.scores = value;
    }
}

window.customElements.define('complementary-board', Board);
window.customElements.define('complementary-guide-color', GuideColor);
window.customElements.define('complementary-choice-colors', ChoiceColors);
window.customElements.define('complementary-choice-color', ChoiceColor);
window.customElements.define('complementary-scores', Scores);
window.customElements.define('complementary-score', Score);

With this, the HTML becomes:

<html>

<head>
    <link rel="stylesheet" href="complementary.css" />
    <script src="complementary.js"></script>
</head>

<body>
    <complementary-board>
    </complementary-board>
</html>

and the CSS:

body {
    width: 100vw;
    height: 100vh;
    margin: 0;
}
complementary-board {
    width:100%;
    height:100%;
    display: grid;
    grid-template-columns: 50% 50%;
    grid-template-rows: min-content auto;
}
complementary-scores {
    grid-column-start: 1;
    grid-column-end: 3;
    grid-row: 1;
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
}
complementary-score {
    display: inline-block;
    padding: 1rem;
    border-radius: 0.5rem;
    background-color: darkgray;
    margin-left: 2px;
}
complementary-score.good {
    background-color: darkgreen;
}
complementary-score.bad {
    background-color: red;
}
complementary-guide-color {
    grid-column: 1;
    grid-row: 2;
}
complementary-choice-colors {
    grid-column: 2;
    grid-row: 2;
    display: flex;
    flex-direction: column;
}
complementary-choice-color {
    flex-grow: 1;
    cursor: pointer;
}
complementary-choice-color[data-result=false] {
    opacity: 0.3;
}

Next

In the next blog posts we will see how we can test our code (we have to make it more testable first!) and how we can use Git as source control. Finally we should have a working game that can be easily modified independently: the visual design, the working code, the structural elements.

and has 0 comments

First of all, what is TaskCompletionSource<T>? It's a class that returns a task that does not finish immediately and then exposes methods such as TrySetResult. When the result is set, the task completes. We can use this class to turn an event based programming model to an await/async one.

In the example below I will use a Windows Forms app, just so I have access to the Click handler of a Button. Only instead of using the normal EventHandler approach, I will start a thread immediately after InitializeComponent that will react to button clicks.

Here is the Form constructor. Note that I am using Task.Factory.StartNew instead of Task.Run because I need to specify the TaskScheduler in order to have access to a TextBox object. If it were to log something or otherwise not involve the UI, a Task.Run would have been sufficient.

    public Form1()
    {
        InitializeComponent();
        Task.Factory.StartNew(async () =>
        {
            while (true)
            {
                await ClickAsync(button1);
                textBox1.AppendText($"I was clicked at {DateTime.Now:HH:mm:ss.fffff}!\r\n");
            }
        },
        CancellationToken.None,
        TaskCreationOptions.DenyChildAttach,
        TaskScheduler.FromCurrentSynchronizationContext());
    }

What's going on here? I have a while (true) block and inside it I am awaiting a method then write something in a text box. Since await is smart enough to not use CPU and not block threads, this approach doesn't have any performance drawbacks.

Now, for the ClickAsync method:

    private Task ClickAsync(Button button1)
    {
        var tcs = new TaskCompletionSource<object>();
        void handler(object s, EventArgs e) => tcs.TrySetResult(null);
        button1.Click += handler;
        return tcs.Task.ContinueWith(_ => button1.Click -= handler);
    }

Here I am creating a task completion source, I am adding a handler to the Click event, then I am returning the task, which I continue with removing the handler. The handler just sets the result on the task source, thus completing the task.

The flow comes as follows:

  1. the source is created
  2. the handler is attached
  3. the task is returned, but does not complete, thus the loop is halted in await
  4. when the button is clicked, the source result is set, then the handler is removed
  5. the task completed, the await finishes and the text is appended to the text box
  6. the loop continues

It would have been cool if the method to turn an event to an async method would have worked like this: await button1.Click.MakeAsync(), but events are not first class citizens in .NET. Instead, something more cumbersome can be used to make this more generic (note that there is no error handling, for demo purposes):

    public Form1()
    {
        InitializeComponent();
        Task.Factory.StartNew(async () =>
        {
            while (true)
            {
                await EventAsync(button1, nameof(Button.Click));
                textBox1.AppendText($"I was clicked at {DateTime.Now:HH:mm:ss.fffff}!\r\n");
            }
        },
        CancellationToken.None,
        TaskCreationOptions.DenyChildAttach,
        TaskScheduler.FromCurrentSynchronizationContext());
    }

    private Task EventAsync(object obj, string eventName)
    {
        var eventInfo = obj.GetType().GetEvent(eventName);
        var tcs = new TaskCompletionSource<object>();
        EventHandler handler = delegate (object s, EventArgs e) { tcs.TrySetResult(null); };
        eventInfo.AddEventHandler(obj, handler);
        return tcs.Task.ContinueWith(_ => eventInfo.RemoveEventHandler(obj, handler));
    }

Notes:

  • is this a better method of doing things? That depends on what you want to do.
  • If you were to use Reactive Extensions, you can turn an event into an Observable with Observable.FromEventPattern.
  • I see it useful not for button clicks (that while true loop scratches at my brain), but for classes that have Completed events.
  • obviously the EventAsync method is not optimal and has no exception handling

and has 2 comments

  You are writing some code and you find yourself needing to call an async method in your event handler. The event handler, obviously, has a void return type and is not async, so when using await in it, you will get a compile error. I actually had a special class to execute async method synchronously and I used that one, but I didn't actually need it.

  The solution is extremely simple: just mark the event handler as async.

  You should never use async void methods, instead use async Task or async Task<T1,...>. The exception, apparently, is event handlers. And it kind of makes sense: an event handler is designed to be called asynchronously.

  More details here: Tip 1: Async void is for top-level event-handlers only

  And bonus: but what about constructors? They can't be marked as async, they have no return type!

  First, why are you executing code in your constructor? And second, if you absolutely must, you can also create an async void method that you call from the constructor. But the best solution is to make the constructor private and instead use a static async method to create the class, which will execute whatever code you need and then return new YourClass(values returned from async methods).

  That's a very good pattern, regardless of asynchronous methods: if you need to execute code in the constructor, consider hiding it and using a creation method instead.

As you possibly know, I am sending automated Tweets whenever I am writing a new blog post, containing the URL of the post. And since I've changed the blog engine, I was always seeing the Twitter card associated with the URL having the same image, the blog tile. So I made changes to display a separate image for each post, by populating the og:image meta property. It didn't work. The Twitter card now refused to show the image. And it was all because the URL I was using was relative to the blog site.

First of all, in order to test how a URL will look in Twitter, use the Twitter Card validator. Second, the Open Graph doesn't specify that the URL in og:image should be absolute, but in practice both Twitter and Facebook expect it to be.

So whenever populating Open Graph meta tags with URLs, make sure they are absolute, not relative.

and has 0 comments

Recently I found out about custom task schedulers and I wanted to blog about all the wonderful things you can do with them. I also imagined new ways of doing await/async by tweaking task schedulers. After hours of attempts, I've come to the conclusion that custom task schedulers are incompatible with await/async and should not be used. Here is why:

  • a task scheduler is used to execute synchronous code inside tasks while async/await code is already asynchronous
  • while async/await code is transformed by the compiler into a state machine with the code that follows being turned into a task that is scheduled on TaskScheduler.Current, the state machine has nothing to do with the task scheduler (see Dissecting the async methods in C#)
  • there are no methods that are both aware of await/async code and a custom task scheduler; by design they are incompatible (see Task.Run vs Task.Factory.StartNew)
  • while a stubborn developer could reproduce the functionality of Task.Run and specify a custom task scheduler, or detect tasks that return tasks and Unwrap them, there are easier and safer ways of doing the same thing without a custom task scheduler
  • as the scheduler will be used not only by the tasks run by the developer, but also by the code separated by await boundaries, the results will be unpredictable except the most simple of scenarios

And a pretty diagram from Microsoft representing the order of the operations and how complex they are. It's not just a case of method executed somewhere, but a complex flow that uses the ThreadPoolTaskScheduler as the default task scheduler as a fundamental low level functionality that should not be changed.

If you need more convincing, consider that the code after an await instruction may not even execute on the same thread (or indeed thread pool) as the one before, even if as written appears part of the same method (see async - stay on the current thread? for more details). More on thread pools from Jon Skeet here: The Thread Pool and Asynchronous Methods.

I have been asking this of people at the interviews I am conducting and I thought I should document the correct answer and the expected behavior. And yes, we've filled the position in for this interview question, so you can't cheat :)

The question is quite banal: given two tables (TableA and TableB) both having a column ID, select the rows in TableA that don't have any corresponding row in TableB with the same ID.

Whenever you are answering an interview question, remember that your thinking process is just as important as the answer. So saying nothing, while better than "so I am adding 1 and 1 and getting 2", may not be your best option. Assuming you don't know the answer, a reasonable way of tackling any problem is to take it apart and try to solve every part separately. Let's do this here.

As the question requires the rows in A, select them:

SELECT * FROM TableA

Now, a filter should be applied, but which one? Here are some ideas:

  1. WHERE ID NOT IN (SELECT ID FROM TableB)
  2. WHERE NOT EXISTS (SELECT * FROM TableB WHERE TableA.ID=TableB.ID)
  3. EXCEPT SELECT ID FROM TableB -- this requires to select only ID from TableA, as well (EXCEPT and INTERSECT are new additions to SQL 2019)

Think about it. Any issues with any of them? Any other options?

To test performance, I've used two tables with approximately 35 million rows. Here are the results:

  1. After 17 minutes I had to stop the query. Also, NOT IN has issues with NULL as a value is nether equal or unequal to NULL. SELECT * FROM Table WHERE Value NOT IN (NULL) for example, will always return no rows.
  2. It finished within 4 seconds. There are still issues with NULL, though, as a simple equality would not work with NULL. Assuming we wanted the non-null values of TableA, we're good.
  3. It finished within 5 seconds. This doesn't have any issues with NULL. SELECT NULL EXCEPT SELECT NULL will return no rows, while SELECT 1 EXCEPT SELECT NULL will return a row with the value 1. The syntax is pretty ugly though and works badly if the tables have other columns

What about another solution? We've exhausted simple filtering, how about another avenue? Whenever we want to combine information from two tables we use JOIN, but is that the case here?

SELECT * FROM TableA a
JOIN TableB b
ON a.ID = b.ID -- again, while I would ask people in the interview about null values, we will assume for this post that the values are not nullable

I've used a JOIN keyword, which translates to an INNER JOIN. The query above will select rows from A, but only those that have a correspondence in B. A funny solution to a slightly different question: count the items in A that do not have corresponding items in B:

SELECT (SELECT COUNT(*) FROM TableA) - (SELECT COUNT(*) FROM TableA a JOIN TableB b ON a.ID = b.ID)

However, we want the inverse of the INNER JOIN. What other types of JOINs are there? Bonus interview question! And the answers are:

  • INNER JOIN - returns only rows that have been successfully joined
  • OUTER JOIN (LEFT AND RIGHT) - returns all rows of one table joined to the corresponding values of the other table or NULLs if none
  • CROSS JOIN - returns all the rows in A joined with all the rows in B and all the rows in B that have no match in A

INNER would not work, as demonstrated, so what about a CROSS JOIN? Clearly not, as it will generate 100 trillion rows before filtering anything. SQL Server would optimize a lot of the query, but it would look really weird anyway.

Is there a solution with OUTER JOIN? RIGHT OUTER JOIN will get the rows in B, not in A, so LEFT OUTER JOIN, by elimination, is the only remaining possible solution.

SELECT a.* FROM TableA a 
LEFT OUTER JOIN TableB b
ON a.ID=b.ID

This returns ALL the rows in table A and for each of them, rows in table B that have the same id. In case of a mismatch, though, for a row in table A with no correspondence in table B, we get a row of NULL values. So all we have to do is filter for those. We know that there are no NULLs in the tables, so here is another working solution, solution 4:

SELECT a.* FROM TableA a 
LEFT OUTER JOIN TableB b
ON a.ID=b.ID
WHERE b.ID IS NULL

This solves the problem, as well, in about 4 seconds. However, the other working solution within the same time (solution 2 above) only works as well because newer versions of SQL server are optimizing the execution. Maybe it's a personal preference from the times solution 4 was clearly the best in terms of performance, but I would chose that as the winner.

Summary

  • You can either use NOT EXISTS (and not NOT IN!) or a LEFT OUTER JOIN with a filter on NULL b values.
  • It's important to know if you have NULL values in the joining columns and it's extra points for asking that from your interviewer
  • If not asking, I would penalize solutions that do not take NULL values in consideration. Extra complexity of code, as one cannot simply check for NULL for solution 4. Also a decision has to be made on the expected behavior when working with NULL values
  • When trying to find the solution to a problem in an interview:
    • think of concrete examples of the problem so you can test your solutions
    • break the problems into manageable bits if possible
    • think aloud, but to the point
  • Also, there is nothing more annoying than doing that thing pupils in school do: looking puppy eyed at the teacher while listing solutions to elicit a response. You're not in school anymore. Examples are dirty, time is important, no one cares about your grades.
  • Good luck out there!

I got this exception that doesn't appear anywhere on Google while I was debugging a .NET Core web app. You just have to enable Windows Authentication in the project properties (Debug tab). Duh!

System.InvalidOperationException: The Negotiate Authentication handler cannot be used on a server that directly supports Windows Authentication. Enable Windows Authentication for the server and the Negotiate Authentication handler will defer to it.
   at Microsoft.AspNetCore.Authentication.Negotiate.PostConfigureNegotiateOptions.PostConfigure(String name, NegotiateOptions options)
   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
   at Microsoft.Extensions.Options.OptionsMonitor`1.<>c__DisplayClass11_0.<Get>b__0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
   at Microsoft.Extensions.Options.OptionsMonitor`1.Get(String name)
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.InitializeAsync(AuthenticationScheme scheme, HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext context, String authenticationScheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

This translates to a change in Properties/launchSettings.json like this:

{
  "iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    //...
  },
  //...
}

I had this annoying warning that appeared whenever I would build my Wix setup project. I know, Wix sucks, but what can you do? The warning was warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "SomeProject\Some.dll", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.

What is worse, the warning would come in the VS Errors window with no warning code, so I couldn't even supress it. And yes, the text above does show a warning code, but it just wouldn't be intrepreted by Visual Studio.

In order to fix it, apparently I had to set ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch to None, as according to this StackOverflow answer. But where should I add this wonderful property? It didn't work in the .wixproj file, it wouldn't make a difference in the projects mentioned in the warning.

In the end, I decided to customize my build! Final solution:

  • add a file called Directory.Build.props to your solution folder
  • paste in it
<Project>
 <PropertyGroup>
   <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
 </PropertyGroup>
</Project>

and has 0 comments

I will show you some code, like in an interview question. Try to figure out what happened, then read on. The question is: what does the following code write to the console:

class Program
{
    static void Main(string[] args)
    {
        var c = new MyClass();
        c.DoWork();
        Console.ReadKey();
    }
}
 
class BaseClass
{
    public BaseClass()
    {
        DoWork();
    }
 
    public virtual void DoWork()
    {
        Console.WriteLine("Doing work in the base class");
    }
}
 
class MyClass:BaseClass
{
    private readonly string _myString = "I've set the string directly in the field";
 
    public MyClass()
    {
        _myString = "I've set the string in the constructor of MyClass";
    }
 
    public override void DoWork()
    {
        Console.WriteLine($"I am doing work in MyClass with my string: {_myString}");
    }
}

Click to expand

and has 0 comments

Let's say you have a Type and you want to find it by the simple name, not the entire namespace. So for string, for example, you want to use Boolean, not System.Boolean. And if you try in your code typeof(bool).Name you get "Boolean" and for typeof(bool).FullName you get "System.Boolean".

However, for generic types, that is not the case. Try typeof(int?). For FullName you get "System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", but for Name you get "Nullable`1".

So the "name" of the type is just that, the name. In case of generics, the name of the type is the same as the name of its generic definition. I find this a bit disingenuous, because in the name you get encoded the fact that is a generic type or not and how many generic type attributes it has, but you don't get the attributes themselves.

I admit that if I had to make a choice, I couldn't have come up with one to satisfy all demands, either. Just a heads up that Type.Name should probably not be used anywhere.

FizzBuzz is a programming task that is often used for job interviews, because it shows the thinking of the candidate in an isolated and concrete case. The requirements may vary slightly, but is goes like this: A loop is going through numbers from 1 to 100. The candidate must write the code in the loop that will display, for each number, a string. This string is: "Fizz" for numbers divisible by 3, "Buzz" divisible by 5 and "FizzBuzz" for numbers that are both divisible by 3 and 5. For all other numbers, just display that number.

There have been many implementations of this, for example my own in JavaScript from a while ago and FizzBuzz Enterprise Edition, which is always a good read about how not to complicate your code. However, since I've last written about it, JavaScript has changed, so I felt compelled to write an updated version. And here it is:
(d=n=>('0369'.includes((f=n=>n>9&&f([...''+n].reduce((s,v)=>+v+s,0))||n)&&f(n))&&'Fizz'||'')+(/[05]$/.test(n)&&'Buzz'||'')||n)*(i=n=>n>100||console.log(n+': '+d(n))+i(n+1))*i(1)

Among the abominations there, some of them inspired by C++ because why not, there are some of the new JavaScript constructs, like arrow functions and the spread operator. I know it seems pointless, but it's not: try to understand what the code does. If you want to see it in action, open Dev Tools in any browser and copy paste it in the console.

A funny feature that I've encountered recently. It's not something most people would find useful, but it helps tremendously with tracing and debugging what is going on. It's easy, just add .TagWith(someString) to your LINQ query and it will generate comments in SQL. More details here: Query tags.

and has 0 comments

One of the best things you could do in software is unit testing. There are tons of articles, including mine, explaining why people should take the time to write code in a way that makes it easily split into independent parts that then can automatically tested. The part that is painful comes afterwards, when you've written your software, put it in production and you are furiously working for the second iteration. Traditionally, unit tests are great for refactorings, but when you are changing the existing code, you need not only to "fix" the tests, but also cover the new scenarios, allow for changes and expansions of existing ones.

Long story short, you will not be able to be confident your test suite covers the code as it changes until you can compute something called Code Coverage, or the amount of your code that is traversed during unit tests. Mind you, this is not a measure of how much of your functionality is covered, only the lines of code. In Visual Studio, they did a dirty deed and restricted the functionality to the Enterprise edition. But I am here to tell you that in .NET Core (and possibly for Framework, too, but I haven't tested it) it's very easy to have all the functionality and more even for the free version of Visual Studio.

These are the steps you have to take:

  • Add coverlet.msbuild NuGet to your unit tests project
  • Add ReportGenerator NuGet to your unit tests project
  • Write a batch file that looks like

    @ECHO OFF
    REM You need to add references to the nuget packages ReportGenerator and coverlet.msbuild
    IF NOT EXIST "..\..\packages\reportgenerator" (
      ECHO You need to install the ReportGenerator by Daniel Palme nuget
      EXIT 1
    )
    IF NOT EXIST "..\..\packages\coverlet.msbuild" (
      ECHO You need to install the coverlet.msbuild by tonerdo nuget
      EXIT 1
    )
    IF EXIST "bin/CoverageReport" RMDIR /Q /S "bin/CoverageReport"
    IF EXIST "bin/coverage.opencover.xml" DEL /F "bin/coverage.opencover.xml"
    dotnet test "Primus.Core.UnitTests.csproj"  --collect:"code coverage" /p:CollectCoverage=true /p:CoverletOutputFormat=\"opencover\" /p:CoverletOutput=\"bin/coverage\"
    for /f "tokens=*" %%a in ('dir ..\..\packages\reportgenerator /b /od') do set newest=%%a
    "..\..\packages\reportgenerator\%newest%\tools\netcoreapp3.0\ReportGenerator.exe" "-reports:bin\coverage.opencover.xml" "-targetdir:bin/CoverageReport" "-assemblyfilters:-*.DAL*" "-filefilters:-*ServiceCollectionExtensions.cs"
    start "Primus Plumbing Code Coverage Report" "bin/CoverageReport/index.htm"​


    and save it in your unit test project folder
  • Optional: follow this answer on StackOverflow to be able to see the coverage directly in Visual Studio


Notes about the batch file:

  • newest is the current version of ReportGenerator, if that doesn't work, change it with whatever version you have (ex: 4.3.0)
  • the DAL filter tells the report to ignore projects with DAL in their name. You shouldn't have to unit test your data access layer.
  • the ServiceCollectionExtensions.cs filter is for files that should be ignored, like extension methods rarely need to be unit tested


Running the batch should start dotnet test and save the result in both coverage.opencover.xml and also some files in the TestResults folder. Then ReportGenerator will generate an html file with the coverage report that will get open at the end. However, if you followed the optional answer, now you are able to open the files in TestResults and see what parts of your code are covered when opened in the Visual Studio editor! I found this less useful than the HTML report, but some of my colleagues liked the option.

I hope this helps you.