Thursday, 3 October 2019

Practical Decisions on Testing: Using TDD

I think this will be the final post in this unplanned series on "Practical Decisions on Testing". Previously posts have covered:

In this post I wanted to consider the topic of test driven development (TDD). It's a technique that tends to divide developers into two camps, those that swear by it, and those that don't touch it (even if they are on board with unit testing itself). Over the course of my career I've used it on occasion, and found some value, but on balance find I fall mostly into the "tests after" camp, and the method of using tests to drive the design of the code isn't something that's really become part of my programming workflow.

In particular, going the full TDD approach where you write code that doesn't initially even compile isn't something I've found grabs me, perhaps due to my background in statically typed languages, primarily C#.

A peer of mine called the approach I generally follow one of "spike and stabilise", which I think (now I Google it) is used in slightly other contexts. But it still fits well I think - write some code that looks like it'll do the job, and then write tests to verify, providing the "double lock" that I think I recall Martin Fowler calling it, that the code is correct. And then, with the tests in place, the red-green-refactor approach can be adopted to improve the code quality whilst maintaining working functionality.

Having said that, I realise there are a couple of occasions where I do use a TDD approach, which I'll detail here. It maybe that others who generally like me don't follow strict TDD, will see there's some situations where it can be a particularly useful technique. Or others, who would like to be doing full TDD but don't yet, can see these as ways into the approach.

The first is following a bug report. Many bugs raised in web development projects that I work on are around rendering issues on different browsers and devices. A true logic error, is rare - as it should be with a solid unit testing approach. If one does appear though, I take that as a affront to the test coverage, and so the first thing to do is to realise there's a missing (or incorrect) test case, and to create a failing test for that. Then we can move on to amend the code to fix the bug, ensuring the test (and all others) go green, and the bug won't reoccur.

A second comes when working with something that is pure logic, like an algorithm. In that case, I find it can be a productive way to work for me, creating tests and the code to make the tests pass iteratively, building up the logic as I go. So whilst I don't find it useful to start tests first when creating an non-compiling MVC controller for example, a single function with some relatively complex logic calculating some value seems to fit better with the technique for me.

Monday, 19 August 2019

Practical Decisions on Testing: Considering a Unit

Without intending to when I started, I've three posts on a topic now, which I think constitutes a series on "Practical Decisions on Testing". Previously posts have covered:

As with the above two posts, the intention I've primarily got is to put down in words some discussions I've had at various times, for a reference and as something to point to.

In this post I want to discuss what we consider as "the unit" when it comes to unit testing. For many developers, it's the class, and the mark of good coverage is to ensure that all public methods - and via them, the private ones - are covered by tests. In doing so, there will certainly be a well tested code base.

There can be a downside discovered in this though, in that it serves as a deterrent for refactoring at the inter-class level. For example, a decision to split the responsibilities of a class into two to better meet the single responsibility principle, is likely going to lead to quite a number of new and changed tests.

This topic is discussed in a great talk shared by a colleague, by Ian Cooper, titled TDD, where did it all go wrong, which is well worth a watch. It's been a while since I did, but I recall taking from it to consider the unit as something that might be higher level than a single class. In doing so, you keep the same level of code coverage but do so by testing the "outer" public methods of the class aggregation, retaining your ability to quickly refactor without so much burden in updating tests.

I also had chance to consider the recently discussing a PR with a colleague, who was asking where the tests for a new class were. The scenario here can be generalised to the following situation. Say you have a class A, with various public methods that are tested. A may well have various dependencies, which in the case of those that are either brittle or slow, are mocked.

On reflection, we decide class A is too big and an extract class refactoring looks useful, creating class B, which then becomes a dependency of A. A's methods that use the functionality of B, now make calls to it via a level of indirection. And as we had good test coverage on class A, we've been able to do this refactoring with the backup of the tests, thus being confident we haven't introduced any new issues.

The question on the PR then was, "where are the tests on the public methods of class B?", and my argument was, there aren't any, and actually, that's OK. Class A is considered the public API that needs testing, whereas class B is an implementation detail, to be considered from a testing perspective no different from private methods in A. And should we refactor further - perhaps collapsing B back into A, or splitting it's responsibilities further - there's again no need for changes to tests.

Similarly, there's no need to create an interface for B and mock it when testing A - we can, and should, just call into it's methods. So rather than considering that "a unit = a class" and that you should mock all dependencies so you test just that one unit; you can expand the thinking to a unit being a "unit of runnable code without slow/brittle dependencies", making it clear there's no need for mocking these dependencies that are "just more code" and aren't components that without mocking would lead to a flaky or slow test base.

Broadly that's the message of Ian's talk as I recall, but I think there's another nuance to it - which is that, whilst it's justified and actually beneficial to avoid writing unit tests for class B's public methods, depending on how this class gets used in the future, that may not always be the case.

Let's say for example class C is developed and also takes a dependency on B, calling into it's methods. Class C has public methods that are unit tested, so we're still all good from a code coverage perspective. We can even extend B, adding some feature that C needs, and with the tests on A and C we're still fully covered. There surely comes a point though when the importance of B to the code-base has increased beyond it's original "helper" status. With more classes referencing and depending on it, it's been upgraded to more of an "application service", and somewhere along this path we'll likely hit a point where we do want to have tests dedicated to B.

Slightly less abstractly, if we consider that A and C are controllers calling into B that was a class holding some business logic, we might well be able to right cleaner, clearer and more thorough tests if we focused directly on the methods and logic of B.

As if often the case with software development best practices and principles, with this topic there's not a black and white rule to follow. As usual, judgement and experience are called in in making another practical decision around when and where to test.

Saturday, 29 June 2019

Practical Decisions on Testing: Code Coverage Metrics

Another short reference post on the topic of unit testing, in the spirit of saving your keystrokes, based on a conversation I've had a couple of times concerning unit test code coverage. We're using Sonarqube on a current project, which, amongst other things, will review C# code and determine the percentage covered by unit tests.

We're currently running at around 80%, which to me seems a fairly healthy metric. It's not the be all and end all of course in that a high percentage of test coverage doesn't completely diagnose a healthy code base, but, all things being equal, it's a good sign.

The question then comes - why not 100%?

Not in the naive sense though - there's clearly areas of the code, property getters and setters being the classic example, that you could unit test, but wouldn't get much if any value in doing so, and hence the effort is unlikely to be worthwhile.

Rather in the sense that if there are areas that's aren't going to be covered in unit tests, we can decorate them with the [ExcludeFromCodeCoverage] attribute, and they'll be excluded from the code analysed for the test coverage metric, thus boosting it.

My view here, is that, when deciding what code should be covered by unit tests, the decision isn't black and white. Some, probably most, code would be better coupled with tests - confirming correct functionality, guiding design if adopting TDD and reducing the likelihood of regression issues - and so the tests should be written along with the feature. On the other hand, as mentioned, some code clearly offers little value in testing, and hence this can immediately be attributed, removing it from analysis, and via a comment, indicate why the decision has been taken to not apply unit tests to the code.

The grey area in between though, is code that is hard to test, and there's some, but not so much, value in doing so - the upper left quadrant as discussed in this previous post. Given that, you might well decide there are more important things to be spending time on right now - such as new feature development or paying off other technical debt. As time goes by though, that cost benefit may shift, as will the set of competing priorities. Given that, it seems best to keep the decision on "should we add tests for this" open, not closing it off by excluding the code from coverage, but rather keep it under review and re-consider doing so, when time and resources may allow.

Wednesday, 1 May 2019

A First Look at ML.Met

I've recently been investigating ML.NET, learning by doing implementing a sample project to try to predict a country's "happiness score" based on various geographic and demographic factors. Cross-posting the resulting blog post shared on Zone's digital output.

Tuesday, 2 April 2019

Umbraco Personalisation Groups: New Release Supporting Umbraco V8

I've published two new releases of the Umbraco Personalisation Groups package, providing personalisation features for websites built on Umbraco, supporting Umbraco 7 and 8.

They are available on Our for download or can be installed via NuGet (though it's best to go the package route for a first install, to help with setup of some necessary document and data types).

With Umbraco 8, a concept of segments and variants has been introduced, that will likely be able to be used for providing similar features. The initial release though only deals with language variants for multi-lingual sites, so, at least for now, think the package will still have some value.

Release Details

There are two new versions of the package:

  • Version 1.0 - targeting Umbraco 7
  • Version 2.0 - targeting Umbraco 8
Umbraco 7 (Personalisation Groups 1.0) Release

This provides almost the same functionality as the most recent 0.3.6 release. I have bumped the major version partly due to it being about time it was on a 1.0 number, but also to reflect the internal restructuring that's occurred to be able to support both versions with the maximum amount of code re-use (there are now two dlls).

There should be no breaking changes in functionality though.

Umbraco 8 (Personalisation Groups 2.0) Release

The release for Umbraco 8 should provide the same functionality as has been available for Umbraco 7, though obviously working with the new release of the CMS platform.

Wrapping Up

Hopefully this new version provides useful to anyone already using the package and migrating to Umbraco 8, or considering using it for a new project. If anyone does find any issues, please feel free to report on the forum or issue tracker.

Sunday, 31 March 2019

Umbraco Mapper: New Releases Supporting Umbraco V8

Today I've published two new versions of the Umbraco Mapper package, a package that supports the use of view models, by mapping Umbraco content to custom view model classes (original thinking was Automapper for Umbraco I guess).

They are available on our.umbraco.org for download or can be installed via NuGet.

I was surprised to see that it's been over 5 years since this package was originally built by myself and some colleagues at Zone - a long time in technology. We're still making use of it though, and as I had some popular demand - well, two people(!) - for a version compatible with the latest Umbraco release, thought it would be good to prepare one.

I've taken an approach of restructuring the solution such that there's a common project, containing non-Umbraco dependent core set of functionality, and then created two Visual Studio projects within the solution, one referencing the Umbraco 7 binaries and one the Umbraco 8 ones. That way, I can support both versions moving forward, and at least minimise the extra effort in terms of duplicated code to maintain moving forward. If all goes as expected, I'll be talking about this technique in more detail, along with other factors involved in upgrading packages to Umbraco 8, in an edition of Skrift near you in a month or so.

Release Details

There are two new versions of the package:

  • Version 3.0 - targeting Umbraco 6 and 7
  • Version 4.0 - targeting Umbraco 8
Umbraco 7 (Umbraco Mapper 3.0) Release

This provides almost the same functionality as the most recent 2.0.9 release. However I have bumped the major version due to a few minor breaking changes, mainly taking the opportunity to streamline a few things.

  • The recursiveProperties string parameter passed to the mapping operations has been removed. This an API design issue from the start really, as it was never necessary, and since support has been added for marking particular view model fields to be mapped recursively via the attributes or the property mapping dictionary you can provide in the mapping call.
  • Have changed the approach to passing a CustomMapping object in the property mapping dictionary to require a type and method rather than a CustomMapping instance itself. This aligns with the use via attribute, and improves internal code re-use as version specific Umbraco dependency is removed.
  • Have added a new FallBackMethods property mapping override and attribute. This isn't necessary to use when targeting version 7 as the only method of "falling back" to retrieve a property value when it's not found on the current content node is recursively, via the ancestors in the tree, when the MapsRecursively boolean attribute or property mapping override can be used. It paves the way though for supporting other methods - namely language fallback, in version 8.

I've also restructured the solution and some namespaces as part of the work to support Umbraco 8, though this shouldn't have any effect for users of the package.

Umbraco 8 (Umbraco Mapper 4.0) Release

The release for Umbraco 8 should provide the same functionality as has been available for Umbraco 7, though obviously working with the new release of the CMS platform.

There are two additional features available though.

One is support for language variants. The signatures for the Map and MapCollection methods have been changed to accept an optional culture code (e.g. "en-GB"), and, if provided, the mapping will use the content from the language variant indicated by the culture code.

    mapper.Map(CurrentPage, model, "en-GB");

The related second addition is the support of fallback methods, so we can ask the mapper to retrieve content from a fallback language if the property value requested has no content (in addition to falling back recursively, via the ancestors in the content tree, as was available before). This can be passed either using a dictionary in the mapping operation:

    mapper.Map(CurrentPage, model, "it",
        new Dictionary<string, PropertyMapping>
            {
                { "HelloText", new PropertyMapping 
                { 
                    FallbackMethods = Fallback.ToLanguage.ToArray() 
                } 
            }
        });

Or by decorating the view model with an attribute:

    public class MyViewModel
    {
        [PropertyMapping(FallbackMethods = new[] { Fallback.Ancestors })]
        public string HelloText { get; set; }
    }

As it's an array, you can even make use of more complicated fallback logic, supported by Umbraco, so you could retrieve content from the fall-back language, and if that fails, via the parent node:

    public class MyViewModel
    {
        [PropertyMapping(FallbackMethods = new[] { Fallback.Language, Fallback.Ancestors })]
        public string HelloText { get; set; }
    }

Wrapping Up

Hopefully this new version provides useful to anyone already using the package and migrating to Umbraco 8, or considering using it for a new project. We'll likely get to put it through it's paces at Zone with some upcoming projects. In the meantime, if anyone does find any issues, please feel free to report on the forum or issue tracker.