Developer Testing Hints and Tips

Howdy happy campers.

I want to discuss a piece, somewhat divergent from the topic of physical coding, although still a facet of development that is close to my heart (and easy to overlook in many respects when constantly mashing keys and churning out code); developer testing. More specifically, I want to provide a set of guidelines that ‘may’ (insert disclaimer) help with the process and provide some food for thought.

This is in no way a definitive guide or best practice for that matter; more just a personal take on what I find works for me and the guts of a generally beneficial ‘templated’ approach to follow.

I would love to invite discussion on this one (or just get a take on what works for you), so please do hit me up on twitter or add a comment below, I’d love to hear from you.

My Process

As with any process, ground work and preparation can be vital for achieving a good result. To this end, I invariably start my developer testing on a given work item with a template document that looks like this:

Illustration of how to structure you Developer Testing.

Developer Testing Helper Document Structure.

What goes into your document will largely depend on what technologies you are using of course. For instance, you may never have a database centric element to the development you perform, rendering the ‘Database Upgrade’ section null and void ‘in all cases’. Ultimately, add and remove sections as you see fit but do strive for consistency. I myself test a mixture of items that may or may not include T-SQL elements. However, I choose to include the ‘Database Upgrade’ section in this case on every occasion, preferring to note that ‘there were no T-SQL’ related parts to the item, even just to mark it as ‘N/A’ (for my own sanity and for easy recollection later down the line, without the need to scan a lengthy list of changes elsewhere in the notes). Basically, my OCD kicks in and I start to wonder why I haven’t included a section that I ‘always’ include, leading to paranoia that I’ve missed something!

Each section (other than Notes), which is probably self-explanatory, can result in a PASS, QUERY or PASS-BACK state. Section state obviously knocks on and influences the result recorded against the ‘Developer Testing Summary’ header. PASS denotes an ‘A-Okay’ state, good to rock and roll! QUERY gives you the opportunity to mark a section with ‘discussion points’ or things you would like to check, without necessarily marking it off as incorrect (I tend to do this a lot, as I love to talk!). PASS-BACK is used in the circumstance whereby an error can be replicated/reproduced consistently or a logic problem definitely flies in the face of the ‘Acceptance Criteria’ for the story. In the circumstances whereby things such as coding standards have been contradicted I tend to use a mixture of QUERY/PASS-BACK, depending on the notes the developer has provided (it could be a flat PASS, of course, as there are always occasions where the rules need to be broken!).

So, section by section, let’s go over what we have and why…

Notes

It’s incredibly tempting to start diving into code, comparing files, trying to make sense of what the hell is going on but…I may get in trouble here, I’m going to tell you to stop right here. It’s so easy, and I’ve done it (probably) hundreds of times, to get eye deep in code, wasting large pots of time, before the basic question of ‘what are we doing and why’ has been answered. This is where this section comes in.

Use this area of your notes to compile a few short paragraphs (or bullet points, whatever you prefer) on the following:

  • Read over the developers notes and, after discovering if any changes have occurred to the underlying requirements for the story, start to create…
  • Your own summary of the ‘Acceptance Criteria’ for this particular story (or item, whatever term floats your boat. I’m going to use both interchangeably to alleviate bombarding you with the same term too much!).
  • Then, list any other pertinent information surrounding how the developer has coded the item (e.g. decisions that have shaped how the story has turned out). For example, did they place code into a different service than was originally expected because of ‘x’ reason, or did some logic end up in a different layer in the technology stack than conceived originally.
  • Lastly, note any of your initial thoughts, concerns or things you intend to check/look for based on this initial scoop of information.

The core reason I do this is to try to solidify my expectations, begin thinking about a test plan (yes, I like to always perform (rudimentary at the bare minimum) application testing, this isn’t just down to QA in my mind!) and to try to mitigate the chances of any massive surprises. Surprises, although they will always eventually happen one way or another, will lead to more confusion and increase the chances of things slipping through the net. You’ll be able to, by just following this exercise or a similar routine, cross-reference your expectations with the code changes you see and more easily be able to pick up errors, incorrect logic or unrequired alterations. This will limit the chances that something will slip past your mental filter as an ‘I guess that’s correct’ or ‘perhaps that class needed to be changed also, ok’ moment (don’t lie, we’ve all had them 😉 !).

Cool, we’ve formed in our own minds what this item is for, how it’s been developed and what, as a baseline, we are expecting to see. Let’s test (and along the way, discuss a few more tactics).

Database Upgrade

Some of what I’ll discuss here is formed around how my personal development role operates, so feel free to modify this approach to your needs. Again, if you don’t deal in the realm of database development at all pass go and collect £200, you’ve bypassed this step; congratulations!

The essence of this section surrounds you being able to state that new Stored Procedures, Functions, Views, Triggers, etc. can be ‘created’ without error on a database in a suitable ‘versioned’ state. Also, can ad-hoc data scripts, that are part of the development item, be run without error?

Some other considerations…

  • Are object creation scripts/ad-hoc scripts expected to be re-runnable? If yes, then specifically test and note this down here.
  • If you are in an environment whereby this kind of testing needs to be performed on multiple databases then mark this down here also (splitting notes down into sections against each target database/environment, whatever is applicable).
  • We work with a ‘versioned’ database so I make an effort to state which version I am on at the start of the testing run for reference.

An example of what this section may look like is illustrated below for reference:

Illustration of how to structure the Database Upgrade Developer Testing Document Section.

Developer Testing Database Upgrade Section Example.

A QUERY/PASS-BACK at this stage will bubble up and alter the status listed for the entire developer testing process. An additional note here; depending on how many queries/issues you find (and the length of the testing notes in general), you may want to copy the core query/error text to the top of the notes for easy review by the developer later (this applies to all of the following sections in fact).

Code Review

Moving on to the main filling of your developer testing sandwich, the actual code review! Obviously, you’ll be reviewing files here and looking at scripts, new files or amended code but definitely take a second or two out (unless your setup has automated builds/continuous integration, or some other clever solution, to tell you this) to make sure the code compiles before proceeding (and make the relevant note). A simple step but one easily forgotten, meaning you can get to the end of a code review before realising parts of the code don’t compile, eek!

I tend to, from a structural and sanity point of view (clarity is key), split my testing notes here into sections based on technology (i.e. T-SQL, C#, JavaScript, etc), or, at least, make some effort to order up a single list of files by file type. I tend to, for C# changes, group code files by the related project (given that projects should represent a logical grouping of types, hence allowing you to dice up changes by functional area, i.e. common extensions, data access helpers, etc.).

The point that you should take away from this, however, is that a little bit of thought and structuring at this phase will make your life easier; especially as a number of code files rack up.

If you’re looking for a small sample on how this section could look, after being fleshed out, then here you go:

Illustration of how to structure the Code Review Developer Testing Document Section.

Developer Testing Code Review Section Example.

However, what about the code review procedure itself I hear you cry! What follows next shouldn’t be taken as an exhaustive list, or correct in every given situation for that matter; more just suggestions as to what I’ve found helpful over time (mental kit bag):

  • For C# (and other object-orientated languages that support this concept), ensure that null values are correctly handled. Whether this is by capturing nulls on call to a given method and throwing an ArgumentNullException, or by doing a ‘not equal to null’ check (!= null) around code that would otherwise fail.
  • Strings can be tricky buggers, especially in case-sensitive environments! In most cases, comparisons should be performed taking case-sensitivity out of the equation (another case-by-case situation of course). I’d keep an eye out, again for C#, for the correct use of String.ToUpperInvariant, String.ToLowerInvariant and String.Equals. For String.Equals, use an overload containing a StringComparison enumeration type, for case/culture-insensitive options.
  • Keep an eye out for instances of checks being performed against strings being null or an empty string (either one or the other only). This can quickly lead to chaos, switch out for a null, empty or whitespace check (e.g. String.IsNullOrWhiteSpace).
  • Empty try/catch handlers are evil. Kill any you find.
  • Check up for instances whereby a class consists of all static members, but the class is not marked as static.
  • Train the eye to look for casting operations; you’ll always catch a few where the casting operation ‘could’ throw exceptions and should, therefore, be subject to more careful handling.
  • Big bugbear in the realm of coding; if a method requires scrolling to get through it’s a significant indication right off the bat that it is a prime candidate for refactoring. Unless there is a good reason, or it is clearly performing one logical function, consider having a conversation about breaking the method down.
  • Look for missed opportunities to rational code using inheritance. The most common one I see (and forget myself) is the abstraction of code to base classes and then using virtual methods/overrides in subclasses. Hawk-eye for types that should be abstract.
  • A simple one, but something that could easily slap you in the face if you’re not careful. When ‘language switching’, in a DT sense, take a second to make a mental note that you should be changing mind-sets (i.e. syntax is changing, get your game-face on!). For example, you stare into the abyss of C# for long enough (seeing ‘!= null’) you may, on switching to T-SQL, not notice a ‘!= NULL’ that should have been an ‘IS NOT NULL’. Those trees can be damn hard to find in the woods, after all!
  • Watch out for expensive operations, whereby values should be obtained once, ideally, then cached. It can be easy to let code skip by that repeatedly calls a database, for instance, to the detriment of performance (or possible errors, depending on the nature of the functionality called).
  • I love, love, loooovvvveeeee comments! Probably (ok, to the levels of being a little OCD about it!) too much. As far as C# code goes, I prefer (but don’t fail on this basis alone) XML Comments for C# and like to see comments on bulkier pieces of T-SQL. If there is a sizeable piece of code, whereby its function stretches beyond ‘trivial’, I like to see at least a short statement stating intent (what the developer is expecting the code to do is key by the way…as discussed next).
  • Where you have comments, link the intent in these comments back to what the code is actually doing; then trail it back to the items ‘Acceptance Criteria’ where appropriate. I have been rescued (as a developer, submitting my work for DT) countless times by those performing DT on my code, just by someone relaying to me that ‘what I thought my code was doing’ (based on my comments) doesn’t tie up to the actual functionality being offered up. This has led to me, of course, face-palming myself but being relieved that the gap in my intent, when checked off against my actual code, had been picked up by somebody in time to catch it before QA (or deployment, gulp!). State intent, then reap the rewards when mistakes you make are more rapidly picked up for rectification.
  • Be sure to look for the use of language constructs/keywords or syntactic-sugar that is not permissible on your baseline, minimum supported environment (i.e. older versions of SQL Server or .NET), if what you work on has this concept of course. This is sure to be something that will get picked up by QA causing bounce backs, or by your consumers later on if you’re not careful!
  • Keep a look out for code that could (or should) be shared or has been placed in a project/location that does not make logical sense. At a bare minimum, picking up on this sooner rather than later will keep your code base tidier, allow for ample opportunities to put great code in places to be leveraged as much as possible. In other cases, asking these kinds of questions can expose flaws and issues with the way a solution has been architected, which occasionally will steer you clear of tight spots later down the line.
  • Where shared code has been changed, look for instances whereby other applications/areas of the code base could be broken as a result of the changes. Recompile code to check for this as required. I had a bite on the bum by this recently :-?.
  • Keep up to date with any coding standards documents that should be adhered to and make sure the guidelines are followed (within reason of course; you’ll always find a scenario whereby a rule can, and should, be broken).
  • Really do consider writing and using Unit Tests wherever possible. They are a useful facet in the grand scheme of things (I believe at least) and they do carry weight when pitched up against visually checking code and application testing in general.
  • Last little nuggets, which I see from time to time. Look for objects constantly being created inside loops, heavy amounts of string concatenation not using the correct constructs (e.g. a StringBuilder in C#) or missed opportunities to create sub Stored Procedures in T-SQL (sectioning off code to gain performance boosts and obtain better execution plans). In fact, for T-SQL it can be a useful exercise to check the performance of non-trivial pieces of code yourself by changing how it’s structured, whilst obtaining the same results of course. You may or may not be able to increase performance along the way, but you’ll have far better comprehension of the code by the end regardless.

Hopefully, this little snapshot from my bag o’ tricks is enough to get you started, or get the brain-juices flowing. Let me know what you think of these suggestions anyway; I’d really appreciate the opportunity to collate others general thoughts and get a collective consensus going.

Application Testing

Here is where I will defer the giving of advice to my beloved QA counterparts on this beautiful planet; this, of course, isn’t my area of expertise. My only opinion here is (developers will possibly hate me for stating it) that developers ‘should’ always perform application testing alongside a code review. In fact, I’m a keen advocate for developers being involved in performing QA on the odd occasion. I personally like doing this, provided I have a trusty QA on hand to assist me (thankfully, I work with the best one around ;-), so no worries there). The simple reasons for this are:

  • One way or the other, acquisition of Product Knowledge is going to be invaluable to you. It’s just as valuable to start using your products in anger as it is to analyse code for hours on end. The side-note here is that this is part of your overall ‘worth’ as a developer, so don’t neglect it.
  • At this stage, you get to think as the customer might. Ideas and thoughts you have at this stage, which direct more development or changes to the product, will be amongst some of the best (and most rewarding when it comes to getting that warm and fuzzy feeling!).
  • Urm…it’s embarrassing to say ‘oh yeah, that codes great, thumbs up!’ for it then to explode in someone else’s face on the first press of a button! Easily avoided by following the process through from end to end, no matter what.

Ok, I’ll have a go at channelling one QA thought. Ok, I got it, here’s one from a mysterious and wise QA guru:

Mysterious and wise guru here… a friendly reminder to developers…never, ever, test your items using only one record! The reason? Well, I’ll test it with more than one record and break it instantly!

If anyone doing QA reads this feel free to feed us your arcane knowledge…God knows we need it! I would advise you keep the original item requirements in mind here of course, whilst testing; securing any process variants in your thoughts that could potentially throw carefully laid plans to waste (e.g. what if we go back and forth from screens x and y between completing process z, or we save the same form information twice, etc.). Your knowledge of the code can help at this stage so use the opportunity whilst you have it.

Before I forgot, an example of this could look like this:

Illustration of how to structure the Application Testing Developer Testing Document Section.

Developer Testing Application Testing Section Example.

Code Review/Application Testing – The Most Important Point…

Do it!!! If you’re not sure (as I am still on a regular basis) then ask the question and run the risk of looking like an idiot! Be a spanner, who cares at the end of the day. I dread to think of how many developers have stared at code and, ultimately, let stuff slide because they refused to pipe up and just say they weren’t sure or ‘didn’t get it’. At the end of the day, it’s better to ask questions and if there turns out to be no issues, or it’s a simple misunderstanding, then no harm, no foul. On a good number of occasions I query things to later realise that I missed a line of code meaning it does work as intended, or there’s some process that had slipped my mind…it hasn’t got me sacked (ahem, yet!). So my advice is just to open up and have a natter at the end of day, it’ll be worth the ratio of ‘idiot’ to ‘bug-saving’ moments, trust me :-).

Admin

As with any process, there will always be (and if there isn’t for you then let me know where you work because it’s awesome!) a certain amount of ‘red tape’. Use this last section to keep track of whether any procedural bits and bobs have been handled. For example, I’m expected to cover the creation of a Release Note (as part of the practices I follow) for any item I work on, so it should be marked down in this section as to whether I’ve completed it or not. It could end up just being a very simple section, like the following:

Illustration of how to structure the Admin Developer Testing Document Section.

Developer Testing Admin Section Example.

I hope this has been helpful and informative; or, at least, got the mind going to start thinking about this process. Again, as mentioned above, I would love to hear your thoughts so please do get in touch either here or via social media.

Cheers all, keep smacking keys and producing coding loveliness in the meantime 🙂

The Importance of Being Lazy

Firstly, apologies are in order…I couldn’t resist the incredibly cheesy title. Secondly, this post has absolutely nothing to do with being lazy (a trait I’m sure is attached to us developers on a regular basis, ahem!), in the traditional sense at least. Nope, today we’ll be looking at the lazy keyword in C# and trying to get an understanding as to how it can be used.

A ‘Lazy’ Explanation

Right, that was the last crap joke and attempt to poke fun at the term ‘lazy’, I promise! So what does this keyword entail and how is it used? The most rudimentary packaged answer is that it allows the developer the necessary control to defer the creation of an ‘expensive’ object (or delay a resource intensive operation) until required by calling code. You may, for example, have a property within one of your classes that although a perfectly valid member (i.e. has a rightful place within the object) may only rarely be required by other members utilising this object. If you couple this with the fact that this object property, hypothetically, at least, is very expensive to create (i.e. a large list or array, a dataset requiring interaction with a database, etc.) then you may find the lazy keyword useful. Here are some further key points to give you a solid grounding in the basics:

  • When used in the appropriate context you can open up opportunities to increase application performance and reduce memory requirements (with the added bonus of easing the pressure on the garbage collector).
  • Allows you to avoid unrequired computations. It’s worth noting here that anything created using the lazy keyword operates on a single instance basis (i.e. you always get returned the same object or value used to initialise the member you are accessing). Examples of this in action are coming right up, so hold on to your hats.
  • Getting access to a lazy members value is, unsurprisingly, achieved via using the ‘.Value’ property (e.g. from the get accessor of a property). More on this later again.
  • Interactions with objects instantiated using the lazy keyword are, by default, thread-safe. There are a few extra discussion points to cover here, which will follow shortly.
  • Ability to write lambdas and use anonymous methods to instantiate a member, writing complex initialisation logic as needed.

I want to scratch the surface on a couple of these points before we proceed to the examples; mainly as I feel a bit more of a detailed discussion wouldn’t go amiss. Firstly, after a root around by myself and a friend at work, the default implementation of a lazy objects thread-safety mechanic (as hinted at in the MSDN documentation) seems to be potentially resource intensive (although hopefully wouldn’t rival the overhead of the objects you intend to work with using this method!). Also, there is the possibility of deadlocks to contend with, albeit a fairly small chance. As we stood on the edge of the diving board and took the plunge, we quickly realised (we did a bit of decompiling to discover this) that thread safety, as far the lazy class goes, involves a fair few lines of code and the utilisation of Monitor.Enter. The end result here is that, depending on usage, you actually may find that you want to alter how locks on lazy objects work (no fast and hard evidence of course, I’m just making you aware of the information should you want to delve deeper and make a more informed decision further down the line).

As an alternative, you can use a constructor consuming a LazyThreadSafetyMode enum value and passing LazyThreadSafetyMode.PublicationOnly through as the value. This provides an alternative strategy to the default locking, whereby all threads ‘race’ to initialise the value (when a member is called simultaneously). One thread initialises the value, and all other threads receive a copy of the ‘same’ object, again only if the ‘Value’ property is called at the same time by multiple threads. Instances created, that ultimately don’t get used, are discarded. As eluded to on MSDN, the end result here is that you mitigate the locking overhead but run the risk of creating and discarding extra copies of an object that is expensive to create (again, it’s stated that this eventuality is unlikely). The end result here is to take all of this onboard and choose your path wisely (a little like picking the right cup in Indiana Jones and the Last Crusade, hopefully without the same severe consequences!).

Something else that could potentially catch you out is, when you use factory methods to initialise a lazy object, that exceptions are cached. In essence, if an exception is thrown the first time a thread accesses a lazy objects Value property this same exception will continue to be thrown on every call (even if conditions change that would otherwise result in a successful call further down the line). This protects us against scenarios whereby we could get subtly different results on different threads and introduces the consistency of ‘on every call, you get the same result’, something which certainly makes sense. A poignant point to be aware of at the very least. MSDN states to add retry logic into the instantiation routine (e.g. the factory method); add this concept to the kit bag at any rate.

Hopefully, this gives you an idea that this, conceptually, can be incredibly useful; with the potential, of course, to lead you quickly up shit creek if you’re not on the ball! For you further delvers and divers, here’s the MDSN documentation to keep you busy:

MDSN Lazy Class Documentation
MSDN Lazy Initialisation

Basic Lazy Usage Examples

We’ve discussed many of the finer points above, so I’ll make sure I’m sticking to business here and will try to keep this as short, and sweet, as possible.

To start us off, we have a basic outline of an Applicant class with some properties and a constructor. Simulating our ‘expensive-to-create’ member, in this case, is the ApplicantExtraDetails object. This has a private backing field and is accessible via a public property. In this implementation, the private backing field for our ApplicantExtraDetails (we could have had a normal property, initialised in the constructor, of course, but I’ve structured it this way for an easier swap out later) is ‘always’ created, regardless of whether calling code uses it.

using System;
using System.Collections.Generic;
using System.Linq;

namespace LazyObjects
{
    /// <summary>
    /// Class that outlines a basic job applicant.
    /// </summary>
    public class Applicant
    {
        #region Public Properties

        /// <summary>
        /// Gets the applicants unique identifier (to be set
        /// via the constructor).
        /// </summary>
        public Guid UniqueApplicantIdentifier { get; }

        /// <summary>
        /// Gets or sets the applicants forename.
        /// </summary>
        public string Forename { get; private set; }

        /// <summary>
        /// Gets or sets the applicants surname.
        /// </summary>
        public string Surname { get; private set; }

        /// <summary>
        /// Gets or sets the applicants core skills.
        /// </summary>
        public List<string> CoreSkills { get; private set; }

        #endregion Public Properties

        #region Expensive Field/Property

        /// <summary>
        /// Private data field that outlines an applicants extra details (a mock object only,
        /// not best practice, just for illustration). Container for other objects.
        /// </summary>
        private ApplicantExtraDetails extraDetails = new ApplicantExtraDetails();

        /// <summary>
        /// Gets the applicants extra details (expensive object to retrieve
        /// and/or hold in memory). May not be required by the caller.
        /// </summary>
        public ApplicantExtraDetails ExtraDetails
        {
            get
            {
                return extraDetails;
            }
        }

        #endregion Expensive Field/Property

        #region Constructor

        /// <summary>
        /// Initialises a new instance of the Applicant class with standard setup data.
        /// </summary>
        /// <param name="uniqueIdent">The applicants unique identifier.</param>
        /// <param name="firstName">The applicants first name.</param>
        /// <param name="lastName">The applicants surname.</param>
        /// <param name="skills">The applicants skills (basic).</param>
        public Applicant(Guid uniqueIdent, string firstName, string lastName, params string[] skills)
        {
            UniqueApplicantIdentifier = uniqueIdent;
            Forename = firstName;
            Surname = lastName;
            CoreSkills = skills.ToList();
        }

        #endregion Constructor
    }
}

Rolling on, here we have the ApplicantExtraDetails type itself, which contains two arrays (that could be, but aren’t, massive) that can hold PersonalInterest and OtherDetail objects respectively.

using System;

namespace LazyObjects
{
    /// <summary>
    /// Class that outlines a job applicant extra details (that may not always be 
    /// required by the caller).
    /// </summary>
    public class ApplicantExtraDetails
    {
        #region Private Data Fields

        /// <summary>
        /// Private data field that outlines an applicant’s personal interests (a mock object only,
        /// not best practice, just for illustration).
        /// </summary>
        private PersonalInterest[] personalInterests = new PersonalInterest[2] { new PersonalInterest(), new PersonalInterest() };

        /// <summary>
        /// Private data field that outlines an applicant’s other details (a mock object only,
        /// not best practice, just for illustration). 
        /// </summary>
        private OtherDetail[] otherDetails = new OtherDetail[2] { new OtherDetail(), new OtherDetail() };

        #endregion Private Data Fields

        #region Public Properties

        /// <summary>
        /// Gets an applicant’s personal interests.
        /// </summary>
        public PersonalInterest[] PersonalInterests
        {
            get
            {
                return personalInterests;
            }
        }

        /// <summary>
        /// Gets an applicant’s other details.
        /// </summary>
        public OtherDetail[] OtherDetails
        {
            get
            {
                return otherDetails;
            }
        }

        #endregion Public Properties

        #region Constructor

        /// <summary>
        /// Initialises a new instance of the ApplicantExtraDetails class with standard setup data.
        /// </summary>
        public ApplicantExtraDetails()
        {
            // Log when this class gets instantiated for illustration purposes
            Console.WriteLine("Applicant Extra Details instantiated!{0}", Environment.NewLine);
        }

        #endregion Constructor
    }
}

The PersonalInterest and OtherDetail classes themselves just contain a single string property, for illustration only, during the upcoming example.

namespace LazyObjects
{
    /// <summary>
    /// Class that outlines a job applicant personal interest (that may not always be 
    /// required by the caller - Part of the ApplicantExtraDetails).
    /// </summary>
    public class PersonalInterest
    {
        #region Getter Only Auto Property

        /// <summary>
        /// Gets the value associated with this 
        /// personal interest (hard coded for illustration).
        /// </summary>
        public string Value => "Test Personal Interest.";

        #endregion Getter Only Auto Property
    }
}

...

namespace LazyObjects
{
    /// <summary>
    /// Class that outlines a job applicant 'other detail' (that may not always be 
    /// required by the caller - Part of the ApplicantExtraDetails).
    /// </summary>
    public class OtherDetail
    {
        #region Getter Only Auto Property

        /// <summary>
        /// Gets the value associated with this 
        /// other detail (hard coded for illustration).
        /// </summary>
        public string Value => "Test Other Detail.";

        #endregion Getter Only Auto Property
    }
}

So, on to the Console Application program class that brings some of this code into scope. For starters, we generate a couple of applicants using fixed values and then add these applicants to a list for iterative processing. The crux during this iterative processing is that only the second applicants ‘Extra Details’ ultimately get interrogated and extracted in this sample…output coming up next.

using System;
using System.Linq;
using System.Collections.Generic;

namespace LazyObjects
{
    /// <summary>
    /// Console program class (for a Lazy Objects test).
    /// </summary>
    class Program
    {
        /// <summary>
        /// Main entry point method.
        /// </summary>
        /// <param name="args">Arguments passed to this application.</param>
        static void Main(string[] args)
        {
            // Generate two unique identifiers for our applicants
            Guid applicantOneUniqueReference = Guid.NewGuid(), applicantTwoUniqueReference = Guid.NewGuid();

            // Generate two test 'applicants' - This data, along with the identifiers, would have been sourced from a database in this example (just hard coded for reference)
            Applicant applicantOne = new Applicant(applicantOneUniqueReference, "James", "Jones", new string[] { "C#", "F#", "C++" }), 
                applicantTwo = new Applicant(applicantTwoUniqueReference, "Brenda", "Reed", new string[] { "HTML", "CSS", "jQuery" });

            // Start processing the applicants...
            Console.WriteLine("Processing applicants...{0}", Environment.NewLine);

            // Doing a foreach to rip out the firstname/surname of each applicant
            List<Applicant> applicants = new List<Applicant>();
            applicants.AddRange(new Applicant[] { applicantOne, applicantTwo });
            applicants.ForEach(app => 
            {
                Console.WriteLine("Firstname: {0}", app.Forename);
                Console.WriteLine("Surname: {0}{1}", app.Surname, Environment.NewLine);

                // Only get and process the 'expensive details' for applicant two
                if (app.UniqueApplicantIdentifier == applicantTwoUniqueReference)
                {
                    app.ExtraDetails.PersonalInterests.ToList().ForEach(item => Console.WriteLine(item.Value));
                    Console.WriteLine();

                    app.ExtraDetails.OtherDetails.ToList().ForEach(item => Console.WriteLine(item.Value));
                    Console.WriteLine();
                }
            });

            // Finished this processing run
            Console.WriteLine("Finished processing...");
            Console.ReadLine();
        }
    }
}

Due to a little logging placed in the constructor of the ApplicantExtraDetails, you can clearly see here that (as we fully expect) both applicants have initialised an object that is not always required.

Console output from a test using no Lazy objects.

Test Using No Lazy Objects.

Ok, a no brainer I hear you say; bread and butter examples always provide a good ‘base camp’ to start from, though. So the problem here is that the object representing the first applicant has been backed into a corner whereby it has been forced to create an ApplicantExtraDetails object on type initialisation, even though only the second applicants ApplicantExtraDetails object property is being used. Let’s change it up to be a little lazier.

Using Lazy Object Instantiation

A minor change has been made to the implementation of the Applicant class to use the generic lazy type. The key thing to note here is that, with the ExtraDetails property, you need to call the ‘.Value’ property to actually obtain the relevant details to return to the caller.

#region Expensive Field/Property

/// <summary>
/// Private data field that outlines an applicant’s extra details (a mock object only,
/// not best practice, just for illustration). Container for other objects. Now using
/// full, Lazy instantiation.
/// </summary>
private Lazy<ApplicantExtraDetails> extraDetails = new Lazy<ApplicantExtraDetails>();

/// <summary>
/// Gets the applicants extra details (expensive object to retrieve
/// and/or hold in memory). May not be required by the caller. Note the 
/// use of .Value now (since the backing field utilised Lazy<T>)./>
/// </summary>
public ApplicantExtraDetails ExtraDetails
{
	get
	{
		return extraDetails.Value;
	}
}

#endregion Expensive Field/Property

The end result is illustrated here, whereby we used exactly the same program class listing above. Two things to note…firstly, notice that the ‘Applicant Extra Details instantiated’ only occurs once, for our second applicant, which is bonza. However, you should also pick up on the fact that the logging of this message now occurs further ‘down the road’ in the application’s lifetime, a nod to the fact that the creation of the object was deferred until it was required.

Console output from a test using Lazy objects.

Test Using Lazy Objects.

For our last wheel spin and handbrake turn, take a look at the last example showing initialisation of a lazy field, using an anonymous method (i.e. factory method) to create the goods.

/// <summary>
/// Example of a static lazy data field.
/// </summary>
private static Lazy<List<string>> lazyStringList = new Lazy<List<string>>(() =>
{
	Console.WriteLine("Getting lazyStringList Value!{0}", Environment.NewLine);

	List<string> newLazyList = new List<string>();
	newLazyList.AddRange(new string[] { "Test one", "Test two", "Test three" });

	return newLazyList;
});

/// <summary>
/// Main entry point method.
/// </summary>
/// <param name="args">Arguments passed to this application.</param>
static void Main(string[] args)
{
	LazyListTest();
}

/// <summary>
/// Lazy static data field test.
/// </summary>
private static void LazyListTest()
{
	// Initialise a couple of lists (initialisation, as the lazy field is static, will occur only once (returns a reference to the same object))
	List<string> testOne = lazyStringList.Value, testTwo = lazyStringList.Value;

	// Iterate over both lists, using an extension
	Console.WriteLine("Iterating over testOne values:");
	testOne.ListItemsToConsole();

	Console.WriteLine("{0}Iterating over testTwo values:", Environment.NewLine);
	testTwo.ListItemsToConsole();

	Console.ReadLine();
}

...

using System;
using System.Collections.Generic;

namespace LazyObjects
{
    /// <summary>
    /// Static extensions class, for illustration only.
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Pushes list items to the console.
        /// </summary>
        /// <param name="targetList">The List to operate on (of the type specified, would not to restrict by type a little more in the real world).</param>
        public static void ListItemsToConsole<T>(this List<T> targetList)
        {
            // We could throw an exception here alternatively, if the list was not correctly instantiated - Preference here just to skip over however
            if (targetList != null && targetList.Count > 0)
            {
                targetList.ForEach(item => Console.WriteLine(item));
            }
        }
    }
}

Here’s the output. The thing to run with here is that the testOne and testTwo lists have both been set using lazyStringList.Value but the factory method initialising lazyStringList was only called once. Remember lazy objects are accessed via the ‘.Value’ property as read-only essentially and the same object is returned on subsequent calls.

Console output from a test using Lazy objects statically.

Test Using Lazy Objects Statically.

I hope this has been a useful tour de force on the subject of lazy objects and, as always, happy coding until the next time!

When are Injections Fun? C# Dependency Injection Deep Dive

Evening all,

This post has been in the works for a while but, due to a wee bit of sickness and a sudden busy schedule outside of work, it’s been waiting in the wings for a little longer than it should have been. Apologies about that guys and girls!

Anyway, I wanted to expose a piece on Dependency Injection. There has been an ongoing slice of development, using this methodology, doing the rounds at work. However, I wanted to look at DI from the perspective of Containers (DI can exist without these, but I’m interested solely in this approach for the time being) and will be using Autofac as the showcase for this.

Dependency Injection In A Nutshell

Dependency Injection essentially encapsulates the idea of producing loosely-coupled, easily testable code whereby classes are not (in the case of coupling DI with interface usage) tied to each other using concrete types. Using a DI Container, it’s also possible for the caller to request an implementation via an interface and retrieve an object on demand, without the need to worry about what other dependencies the type requested may require. When things are interface-centric, it’s also a cinch to override implementations and, off the back of this, unit test specific type behaviour in a more isolated way.

The best explanation you’ll find, without a shadow of a doubt, is this one (enjoy!):

How to explain dependency injection to a 5-year-old?

When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.

What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.

Dependency Injection Sample

What follows is a fairly trivial application that implements an Autofac DI Container, and shows off a few basic DI concepts to boot. Firstly, here are the resources that I used to kick start this project:

Autofac Documentation
Autofac NuGet Gallery Reference

I found this particular TechEd video particularly interesting. It covers DI and Container usage from the perspective of Autofac, Unity and many others (although, leans more towards Autofac as the examples begin to get more fleshed out):

Deep Dive into Dependency Injection and Writing Decoupled Quality Code and Testable Software

This first snippet of code outlines the entry point for a small Console Application. The ConfigureApplicationContext method constructs a ContainerBuilder object, which is part of the Autofac namespace, using a RegisterApplicationTypes helper method. This method illustrates, on application start, the linking of interface types to concrete implementations. Notice the addition of the ‘SingleInstance’ call against the registration of the IConfigurationHelper implementing type, this is an interesting nugget that forces the same instance of a class, as opposed to a new instance, to be retrieved when required (via a request to the DI Container).

The FileCleaner classes Run method is then called (I’ve used a concrete type at this level but, of course, I could have referenced this via an interface also). The FileCleaner class constructor accepts, for the purposes of resolving types from the DI Container, an IProcessorLocator implementing object. You’ll see this isn’t passed in per say, the call to Application.Container.Resolve takes care of this ‘dependency’ for use, magic! You’ll see how the IProcessorLocator object gets used specifically in later examples (the comments here also expand on the concepts at work, so be sure to have a sift through).

using Autofac;
using DesktopCleaner.Helpers;
using DesktopCleaner.Implementations;
using DesktopCleaner.Interfaces;
using DesktopCleaner.Locators;
using System;

namespace DesktopCleaner
{
    /// <summary>
    /// Console Application Program Class, containing this applications
    /// entry point (Main) method.
    /// </summary>
    class Program
    {
        #region Constructor

        /// <summary>
        /// Static Main method representing this applications
        /// entry point.
        /// </summary>
        /// <param name="args">Any arguments from external sources.</param>
        static void Main(string[] args)
        {
            // Configure this applications DI Container
            ConfigureApplicationContext();
        }

        #endregion Constructor

        #region Private Static Helper Methods

        /// <summary>
        /// Private static helper method that configures this applications
        /// DI Container fully, ready for the applications life-time (as well
        /// as kicking off the core processing of this application via a FileCleaner instance).
        /// </summary>
        private static void ConfigureApplicationContext()
        {
            // Use the Autofac ContainerBuilder type to construct interface/concrete type mappings
            ContainerBuilder builder = RegisterApplicationTypes();

            // Construct our DI Container (for general use throughout the lifetime of our application in this case)
            Application.Container = builder.Build();

            // Create a cleanerHelper and 'run it' (the objects constructor will receive an IProcessLocator implementing object (ProcessorLocator) in this case due to the previous mappings)
            FileCleaner cleanOperationHelper = Application.Container.Resolve<FileCleaner>();
            if (cleanOperationHelper.Run())
            {
                Console.WriteLine("Cleaning Completed Successfully!");
            }
            else
            {
                Console.WriteLine("Cleaning Failed. Please check the logs (what a joke, there are none!).");
            }

            // Halt application before exit so we can inspect the output
            Console.ReadLine();
        }

        /// <summary>
        /// Private static helper method that creates a ContainerBuilder
        /// to map interfaces to concrete types (for DI loveliness). Return the builder
        /// to the caller (we're using this to called builder.Build() to setup our 'Container').
        /// </summary>
        /// <returns></returns>
        private static ContainerBuilder RegisterApplicationTypes()
        {
            // Instantiate a builder and map types as required
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<FileCleaner>();
            builder.RegisterType<ConfigurationHelper>().As<IConfigurationHelper>().SingleInstance();    // A special case here, demonstrate the use of SingleInstance()
            builder.RegisterType<FileHelper>().As<IFileHelper>();
            builder.RegisterType<ProcessorLocator>().As<IProcessorLocator>();                           // A cool little utility to get instances (so we don't have to new-up in classes using concrete types)

            return builder;
        }

        #endregion Private Static Helper Methods
    }
}

Absolutely not required, just for illustration purposes only, the following static class is simply used as an application level helper (for global access to the container). Not necessarily how you’d structure it, but makes the examples coming up easier to manoeuvre through.

using Autofac;

namespace DesktopCleaner.Helpers
{
    /// <summary>
    /// Public static class that holds application constants
    /// and shared helpers.
    /// </summary>
    public static class Application
    {
        #region Public Static Properties (CORE DI CONTAINER)

        /// <summary>
        /// Public static property (for use across this application
        /// </summary>
        public static IContainer Container { get; set; }

        #endregion Public Static Properties (CORE DI CONTAINER)

        #region Public Constants

        /// <summary>
        /// Public constant string representing the DesktopAppSettingKey
        /// key value (in the app.config).
        /// </summary>
        public const string DesktopAppSettingKey = "DesktopPath";

        #endregion Public Constants
    }
}

Next up, we need some interfaces. These represent key processes that our application is expected to implement (the catch being that these interfaces will be used to retrieve concrete implementations on demand, without the need to use the ‘new’ keyword in our classes). Note the last interface in this list, IProcessorLocator. Again, this is a linchpin type that will be passed to each class to retrieve all manner of other types (due to its use of a generic method) on demand. The result being here that using an IProcessorLocator, as a container wrapper, negates the need to pass multiple interfaces to a type’s constructor. We just pass this one interface supporting object instead (and this also means we don’t need data fields to store these instances either).

namespace DesktopCleaner.Interfaces
{
    /// <summary>
    /// Public ICleanerHelper support interface definition.
    /// </summary>
    public interface ICleanerHelper
    {
        #region Interface Methods

        /// <summary>
        /// Public method for ICleanerHelper support representing
        /// behaviour for a 'run' process method.
        /// </summary>
        /// <returns>True if the run processing is successful, otherwise false.</returns>
        bool Run();

        #endregion Interface Methods
    }
}

...

using System.Collections.Specialized;

namespace DesktopCleaner.Interfaces
{
    /// <summary>
    /// Public ICleanerHelper support interface definition.
    /// </summary>
    public interface IConfigurationHelper
    {
        #region Interface Methods

        /// <summary>
        /// Public method for IConfigurationHelper support to allow for behaviour
        /// to retrieve a 'setting' based on a 'key'.
        /// </summary>
        /// <param name="key">The key to transpose to a value.</param>
        /// <returns>The value that links to the specified key.</returns>
        string GetConfigurationSetting(string key);

        /// <summary>
        /// Public method for IConfigurationHelper support to allow for behaviour
        /// to retrieve a collection of 'setting' keys and values.
        /// </summary>
        /// <returns>A collection of settings (specialised NameValueCollection).</returns>
        NameValueCollection GetAllConfigurationSettings();

        #endregion Interface Methods
    }
}

...

using System.Collections.Generic;

namespace DesktopCleaner.Interfaces
{
    /// <summary>
    /// Public IFileHelper support interface definition.
    /// </summary>
    public interface IFileHelper
    {
        #region Interface Methods

        /// <summary>
        /// Public method for IFileHelper support to allow for behaviour
        /// to get a list of files based on the specified path (in some manner, based on implementation).
        /// </summary>
        /// <param name="path">The directory path to be used.</param>
        /// <returns>A list of files relating to the directory specified.</returns>
        List<string> GetFilesForPathAsList(string path);

        /// <summary>
        /// Public method for IFileHelper support to allow for behaviour
        /// to process a list of file names (in some manner, based on implementation). 
        /// </summary>
        /// <param name="fileList">Represents the list of files to operate on.</param>
        /// <returns>A boolean to represent if processing was successful.</returns>
        bool ProcessFiles(List<string> fileList);

        #endregion Interface Methods
    }
}

...

namespace DesktopCleaner.Interfaces
{
    /// <summary>
    /// Public IProcessorLocator support interface definition.
    /// </summary>
    public interface IProcessorLocator
    {
        #region Interface Methods

        /// <summary>
        /// Public method for IProcessorLocator support to allow for behaviour
        /// to get a 'processor' for any specified interface type (this should be constrained more
        /// in an ideal world).
        /// </summary>
        /// <typeparam name="T">The type to retrieve a processor class based on.</typeparam>
        /// <returns>A concrete class, depending on the implementation.</returns>
        T GetProcessor<T>();

        #endregion Interface Methods
    }
}

Here we have another ‘illustrative’ class that, as you’ll remember from our DI Container configuration, is marked as ‘Single Instance’ (just as an example). It simply interrogates the AppSettings of the app.config file to retrieve information, as required by calling code.

using DesktopCleaner.Interfaces;
using System.Collections.Specialized;
using System.Configuration;

namespace DesktopCleaner.Implementations
{
    /// <summary>
    /// Public ConfigurationHelper class that implements IConfigurationHelper
    /// to interrogate the applications app.config file (implementation can
    /// be modified however, as per the DesktopCleaner.UnitTests).
    /// </summary>
    public class ConfigurationHelper : IConfigurationHelper
    {
        #region Public Expression Bodied Methods

        // Again, illustration only, may abstract this into a differing format (use of lazy/properties, etc) - Methods are for demo purposes (for mocking up a functional class for DI usage)

        /// <summary>
        /// Gets access to the applications app.config AppSetting
        /// key/value pairs (as is).
        /// </summary>
        /// <returns></returns>
        public NameValueCollection GetAllConfigurationSettings() => ConfigurationManager.AppSettings;

        /// <summary>
        /// Gets access to the a particular AppSetting value, from the app.config
        /// file, based on the provided key.
        /// </summary>
        /// <param name="key">The AppSetting key to use when searching for a corresponding value.</param>
        /// <returns>A string denoting the matching value (based on key).</returns>
        public string GetConfigurationSetting(string key) => ConfigurationManager.AppSettings[key];

        #endregion Public Expression Bodied Methods
    }
}

The next couple of classes represent the bulk of our test application. There is nothing super special or uber magical here, so it should be easy to stick with. The idea behind this application is to move files from one location to another, tidying files after a successful move. This is all tied to configuration found in the app.config (which can, of course, be overridden as demonstrated later on by some example unit tests). Due to the use of interfaces, the implementation itself could differ greatly, however.

The key code lies in the constructor, that assigns a private data field with an object supporting the IProcessorLocator interface, allowing for type resolution in the other core methods in this class. Within the Run method the ‘processor locator’ is finally utilised to, on demand, locate and retrieve instances of IConfigurationHelper and IFileHelper supporting objects. We could, of course, have foregone the use of the ProcessLocator, and passed in all required interface types into this objects constructor. However, we would have incurred penalties for unrequired object creation and storage for types that, in reality, may not even be used by calling code (in this example I’m utilising all of the types anyway, but just mark it as a side note!). We have an example of some loosely-coupled code!

The CompareObjectsInDebug method is there just to illustrate that the call to processorLocator.GetProcessor is retrieving new objects/single instances as expected.

using DesktopCleaner.Helpers;
using DesktopCleaner.Interfaces;
using System;

namespace DesktopCleaner.Implementations
{
    /// <summary>
    /// Public class that represents a 'File Cleaner', supporting
    /// a Run method for processing and cleaning desktop files.
    /// </summary>
    public class FileCleaner : ICleanerHelper
    {
        #region Private Data Fields

        /// <summary>
        /// Private data field that represents this types processor locator (that
        /// will contain an instance of a class implementing this interface for 
        /// grabbing concrete types to perform operations.
        /// </summary>
        private IProcessorLocator processorLocator;

        #endregion Private Data Fields

        #region Constructor

        /// <summary>
        /// Instantiates a new FileCleaner object; Autofac deals with
        /// the passing of an IProcessorLocator supporting object (or Moq
        /// handles this when Unit Tests are involved).
        /// </summary>
        /// <param name="locator">An IProcessorLocator implementing object (for this class to support various forms of functionality).</param>
        public FileCleaner(IProcessorLocator locator)
        {
            processorLocator = locator;
        }

        #endregion Constructor

        #region Public Methods

        /// <summary>
        /// Public method that performs the core operation of this class. We obtain 
        /// information from the app.config, retrieve files from the designated desktop
        /// location and process them (i.e. copy to a set location and delete the originals).
        /// </summary>
        /// <returns>A boolean that denotes if this operation completed successfully.</returns>
        public bool Run()
        {
            Console.WriteLine("Running the cleaner helper!");

            // Use this instances IProcessLocator supporting object to get instances of classes supporting the IConfigurationHelper and IFileHelper interfaces
            // for retrieving files and subsequently processing them
            IConfigurationHelper configurationHelper = processorLocator.GetProcessor<IConfigurationHelper>();
            IFileHelper fileHelper = processorLocator.GetProcessor<IFileHelper>();

#if DEBUG
            // In debug, performing a little extra output logging to illustrate object setup (The IConfigurationHelper implementing object is set up as 'Single Instance', so we want to illustrate this)
            CompareObjectsInDebug(configurationHelper, fileHelper);
#endif

            // We have our objects, now run the 'process' and see if it completes successfully
            bool operationSuccessful = false;

            try
            {
                operationSuccessful = fileHelper.ProcessFiles(fileHelper.GetFilesForPathAsList(configurationHelper.GetConfigurationSetting(Application.DesktopAppSettingKey)));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return operationSuccessful;
        }

        #endregion Public Methods

        #region Private Helper Methods

        /// <summary>
        /// Private helper method that does a little bit of extra object
        /// interrogation and output, in debug mode, to show object configuration.
        /// </summary>
        /// <param name="configurationHelper">The IConfigurationHelper object passed from the caller (for comparison).</param>
        /// <param name="fileHelper">The IFileHelper object passed from the caller (for comparison).</param>
        private void CompareObjectsInDebug(IConfigurationHelper configurationHelper, IFileHelper fileHelper)
        {
            Console.WriteLine();

            // Create two new objects using the process locator - We want to see if the IConfigurationHelper supporting object is Single Instance, as opposed to the IFileHelper supporting object
            IConfigurationHelper configurationHelper2 = processorLocator.GetProcessor<IConfigurationHelper>();
            IFileHelper fileHelper2 = processorLocator.GetProcessor<IFileHelper>();

            // What are dealing with (additional debug info only) - Actual do the object interrogation; first on Hash Codes
            Console.WriteLine("configurationHelper HashCode: {0}", configurationHelper.GetHashCode());
            Console.WriteLine("configurationHelper2 HashCode: {0}", configurationHelper2.GetHashCode());
            Console.WriteLine("fileHelper HashCode: {0}", fileHelper.GetHashCode());
            Console.WriteLine("fileHelper HashCode: {0}", fileHelper2.GetHashCode());

            // ...Then on an actual 'equals' check
            Console.WriteLine("configurationHelper == ConfigurationHelper2: {0}", configurationHelper == configurationHelper2);
            Console.WriteLine("fileHelper == fileHelper2: {0}", fileHelper == fileHelper2);

            Console.WriteLine();
        }

        #endregion Private Helper Methods
    }
}

The next class, apart from being an example of very, very incomplete exception handling (gulp!) shows a similar pattern to the above class again. The IProcessorLocator object is passed in, as a dependency, to this object’s constructor (when it is resolved and retrieved by an object that requires it) and then utilised to retrieve types to perform the relevant class functions as needed.

This is essentially the workhorse class, handling files, performing the move and delete operations and then reporting the result (in the form of a boolean) to the caller. I’ve utilised a couple of private helper methods, just as processing aids (which could be changed as required/exposed also as public implementations to be overridden).

using DesktopCleaner.Helpers;
using DesktopCleaner.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace DesktopCleaner.Implementations
{
    /// <summary>
    /// Public class that represents a 'File Helper', supporting
    /// various methods for obtaining files and cleaning directories.
    /// </summary>
    public class FileHelper : IFileHelper
    {
        #region Private Data Fields

        /// <summary>
        /// Private data field that represents this types processor locator (that
        /// will contain an instance of a class implementing this interface for 
        /// grabbing concrete types to perform operations.
        /// </summary>
        private IProcessorLocator processorLocator;

        #endregion Private Data Fields

        #region Constructor

        /// <summary>
        /// Instantiates a new FileHelper object; Autofac deals with
        /// the passing of an IProcessorLocator supporting object (or Moq
        /// handles this when Unit Tests are involved).
        /// </summary>
        /// <param name="locator">An IProcessorLocator implementing object (for this class to support various forms of functionality).</param>
        public FileHelper(IProcessorLocator locator)
        {
            processorLocator = locator;
        }

        #endregion Constructor

        #region Public Methods

        /// <summary>
        /// Public method that, based on a provided path, will return
        /// files in the given directory in the form of a List<string>.
        /// </summary>
        /// <param name="path">The path to return files for.</param>
        /// <returns>A list of type string representing files in the given directory.</returns>
        public List<string> GetFilesForPathAsList(string path)
        {
            // Two phases of validation here. Ensure the path provided is set and is valid (treating these as both exceptional circumstances in my scenario, could be debated of course)
            if (string.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (!Directory.Exists(path))
            {
                throw new InvalidOperationException("GetFilesForPathAsList called with a path that does not resolve to a valid directory");
            }

            // Attempt to set the directoryFileList so the data can be returned to the caller
            List<string> directoryFileList = null;

            try
            {
                directoryFileList = Directory.GetFiles(path).ToList();
            }
            catch (Exception ex)
            {
                // TODO (LOL!) - Log
                Console.WriteLine(ex.Message);
            }
            
            return directoryFileList;
        }

        /// <summary>
        /// Public method that serves as the main work-horse for this class.
        /// We consume a file list and, based on app.config AppSetting pathing information,
        /// decided on where to copy files based on extensions (subsequently deleting them from
        /// the original file location after copy).
        /// </summary>
        /// <param name="fileList">The list of files to operate on.</param>
        /// <returns>A boolean representing if the process was a success (fails on first error in its current form).</returns>
        public bool ProcessFiles(List<string> fileList)
        {
            // Phase one validation only, just ensure the file list is set correct (i.e. not null)
            if (fileList == null)
            {
                throw new ArgumentNullException(nameof(fileList));
            }

            bool filesProcessedSuccessfully = false;

            // Not the greatest here! For illustration only, get a class instance to interrogate app.config AppSettings and use this information to clean the file list data
            try
            {
                IConfigurationHelper configurationHelper = processorLocator.GetProcessor<IConfigurationHelper>();

                List<KeyValuePair<string, string>> appSettings = GetAppSettingsForFileProcessing(configurationHelper);
                CopyAndDeleteFilesBasedOnAppSettings(fileList, appSettings);

                // If we get here then we're successful (by definition that the code didn't error only, of course!)
                filesProcessedSuccessfully = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return filesProcessedSuccessfully;
        }

        #endregion Public Methods

        #region Private Static Helper Methods

        /// <summary>
        /// Private static helper method that uses the provided IConfigurationHelper to 
        /// retrieve AppSettings as a KeyValuePair list (essentially just for convenience).      
        /// /// </summary>
        /// <param name="configurationHelper">The IConfigurationHelper supporting class to retrieve settings based on.</param>
        /// <returns>A list of type KeyValuePair containing the various settings.</returns>
        private static List<KeyValuePair<string, string>> GetAppSettingsForFileProcessing(IConfigurationHelper configurationHelper)
        {
            // Prepare a KeyValuePair list for storing the settings in a more convenient format
            List<KeyValuePair<string, string>> appSettings = new List<KeyValuePair<string, string>>();

            // Using a little linq, get every AppSetting key and value and add it to the appSettings list (ignoring the DesktopAppSettingKey, we don't need this for file processing, so pretty much hard coded for purpose :o) )
            configurationHelper.GetAllConfigurationSettings().AllKeys.Where(appSettingKey => !appSettingKey.Equals(Application.DesktopAppSettingKey, StringComparison.InvariantCultureIgnoreCase)).ToList().ForEach(appSettingKey =>
            {
                appSettings.Add(new KeyValuePair<string, string>(appSettingKey, configurationHelper.GetConfigurationSetting(appSettingKey)));
            });

            // Return the results to the caller
            return appSettings;
        }

        /// <summary>
        /// Private static helper method that consumes a file list and 'settings' to perform
        /// a copy and delete process on each file.
        /// </summary>
        /// <param name="fileList">The files to operate on.</param>
        /// <param name="appSettings">The settings to apply to the files regarding copy and delete processing.</param>
        private static void CopyAndDeleteFilesBasedOnAppSettings(List<string> fileList, List<KeyValuePair<string, string>> appSettings)
        {
            // Loop through each file to process individually (just for illustration)
            string copyLocation = null, fileNameOnly = null;
            fileList.ForEach(file =>
            {
                // Retrieve the file name (only) associated with the path, and log to the console
                fileNameOnly = Path.GetFileName(file);
                Console.WriteLine("Attempting to clean: {0}", fileNameOnly);

                // Retrieve the copy location for this particular file extension, if one is set (again, probably better ways to do this, illustration only)
                copyLocation = appSettings.FirstOrDefault(item => item.Key.Equals(Path.GetExtension(file).Remove(0, 1), StringComparison.InvariantCultureIgnoreCase)).Value;

                // If we have a location to copy to then attempt to perform the copy (then delete the file afterwards from its original location). Failure will halt the process
                if (!string.IsNullOrWhiteSpace(copyLocation))
                {
                    File.Copy(file, Path.Combine(copyLocation, fileNameOnly));
                    File.Delete(file);
                }
            });
        }

        #endregion Private Static Helper Methods
    }
}

Lastly, here is the (very, very simple as it turns out!) wrapper for our DI Container, the ProcessorLocator (implementing IProcessorLocator).

using Autofac;
using DesktopCleaner.Helpers;
using DesktopCleaner.Interfaces;

namespace DesktopCleaner.Locators
{
    /// <summary>
    /// Public class that represents a 'Processor Locator', which
    /// just obtains concrete class based on the DI Container in the Program
    /// class (held statically in the DesktopCleaner.Helpers.Application class, which
    /// is set up when this application is started).
    /// </summary>
    public class ProcessorLocator : IProcessorLocator
    {
        #region Public Expression Bodied Methods

        /// <summary>
        /// Based on T provide a concrete class implementation
        /// (that matches the interface in the DI Container).
        /// </summary>
        /// <typeparam name="T">The interface to get a concrete type based on.</typeparam>
        /// <returns>An instance of the concrete class, as mapped.</returns>
        public T GetProcessor<T>() => Application.Container.Resolve<T>();

        #endregion Public Expression Bodied Methods
    }
}

Just for kicks! For anyone wondering what is found in the app.config, here it is for reference:

<!--App Setting Configuration example (within the app.config)-->
<appSettings>
  <add key="DesktopPath" value="C:\Users\fakeuser\Desktop\Imaginary_Desktop"/>
  <add key="jpg" value="C:\Users\fakeuser\Desktop\Imaginary_Desktop\jpeg_folder"/>
  <add key="url" value="C:\Users\fakeuser\Desktop\Imaginary_Desktop\url_folder"/>
  <add key="txt" value="C:\Users\fakeuser\Desktop\Imaginary_Desktop\txt_folder"/>
  <add key="xlsx" value="C:\Users\fakeuser\Desktop\Imaginary_Desktop\xslx_folder"/>      
</appSettings>

Another reference piece just to finish up before we inspect the actual output; a class diagram for the application as it stands (pretty flat and easy to understand):

Desktop Cleaner class diagram showing application structure.

Desktop Cleaner Class Diagram.

So, what do you get when you run this application? The next screenshot should hopefully give a good indication as to what is going on ‘under the hood’.

Here’s the final output, with the most interesting portion of output being in the first section, showing some details about the objects retrieved from the DI Container (using the ProcessorLocator class). This shows that IFileHelper instances (FileHelper in this case) are retrieved as new instances, whereby the IConfigurationHelper instances are single instances as expected (as per the DI Container configuration):

Console output from the Desktop Cleaner application.

Desktop Cleaner Report.

We now have a rough sample of loosely coupled code without concrete implementations embedded. Let’s have a look at the implications for unit testing.

DI and Unit Testing (Moq)

Does this methodology actually help during a basic unit testing scenario? I’ll be using Moq to find out:

Autofac.Extras.Moq NuGet Gallery Reference

In this example, we (after doing a little bit of setting up) utilise the AutoMock.GetLoose (get automatic mocks using loose mocking behaviour) method to retrieve a type to generate our ‘systems under test’ (i.e. other classes). The coolest thing here is that, as demonstrated by the FileHelperProcessFilesTest method, is the injection of the testMoqConfigurationHelper (which is retrieved when the type under test utilises an IProcessLocator to retrieve an IConfigurationHelper supporting object). This way, we are able to ‘rig’ certain parts of an implementation to focus down our unit tests to only specific areas of business logic, certainly very neat indeed. I’ve included all of the implementation code for reference (all commented to add clarity where required).

More details can be found here for those who want to delve a little deeper in Moq:

Moq Documentation

using Autofac.Extras.Moq;
using DesktopCleaner.Implementations;
using DesktopCleaner.Interfaces;
using DesktopCleaner.UnitTests.Helpers;
using DesktopCleaner.UnitTests.MoqObject;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace DesktopCleaner.UnitTests
{
    /// <summary>
    /// Public class that holds all of the Unit Test logic to
    /// run Moq tests against the DesktopCleaner application.
    /// </summary>
    [TestClass]
    public class DesktopCleanerTests
    {
        #region Private Static Data Fields (For Unit Tests)

        /// <summary>
        /// Private data fields that represent paths for directories
        /// to used during these unit tests (purely for demonstration).
        /// </summary>
        private static string testDesktopPath = Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder),
            testTxtFilesPath = Path.Combine(testDesktopPath, SharedTestValues.TestTxtFilesFolder),
            testSqlFilesPath = Path.Combine(testDesktopPath, SharedTestValues.TestSqlFilesFolder);

        #endregion Private Static Data Fields (For Unit Tests)

        #region Test Class Initialisation Logic

        /// <summary>
        /// Public method that sets up the required resources for all
        /// of the Unit Tests featured in this class. NOTE: There is a requirement 
        /// for all of the tests to run (you wouldn't want to introduce a 'link' between all
        /// of your tests in production, but as I'm doing a demo this is permissible for now).
        /// </summary>
        /// <param name="context">The TestContext object for this class.</param>
        [ClassInitialize]
        public static void ConfigureTestResources(TestContext context)
        {
            // Create a Test Desktop folder and a TXT/SQL folder as sub-directories (ready to receive content in the tests below)
            Directory.CreateDirectory(testDesktopPath);
            Directory.CreateDirectory(testTxtFilesPath);
            Directory.CreateDirectory(testSqlFilesPath);

            // Add four tests files, two SQL files and two standard TXT file, into the root directory (for 'cleaning' during the unit tests)
            File.Create(Path.Combine(testDesktopPath, SharedTestValues.TestTxtFileNameOne)).Close();
            File.Create(Path.Combine(testDesktopPath, SharedTestValues.TestTxtFileNameTwo)).Close();
            File.Create(Path.Combine(testDesktopPath, SharedTestValues.TestSqlFileNameOne)).Close();
            File.Create(Path.Combine(testDesktopPath, SharedTestValues.TestSqlFileNameTwo)).Close();
        }

        #endregion Test Class Initialisation Logic

        #region Public Static Test Methods

        /// <summary>
        /// Public test method that runs an implementation test against
        /// a FileHelper class and the GetFilesForPathAsList method.
        /// </summary>
        [TestMethod]
        public void FileHelperGetFilesForPathAsListTest()
        {
            using (AutoMock mock = AutoMock.GetLoose())
            {
                // Arrange (i.e. configure the mock)
                FileHelper sut = mock.Create<FileHelper>();

                // Act
                List<string> directoryList = sut.GetFilesForPathAsList(new MoqConfigurationHelper().GetConfigurationSetting(SharedTestValues.DesktopTestAppSettingKey));

                // Assert
                Assert.AreEqual(4, directoryList.Count);
            }
        }

        /// <summary>
        /// Public test method that runs an implementation tests against
        /// a FileHelper class and the ProcessFiles method primarily (ensuring that 
        /// the FileHelper receives a 'mock' version of an IConfigurationHelper for 
        /// testing purposes, which returns a predefined configuration to test against).
        /// </summary>
        [TestMethod]
        public void FileHelperProcessFilesTest()
        {
            using (AutoMock mock = AutoMock.GetLoose())
            {
                // Arrange (i.e. configure the mock)
                MoqConfigurationHelper testMoqConfigurationHelper = new MoqConfigurationHelper();

                // This is the interesting bit - Pass the MoqConfigurationHelper as our implementation of IConfigurationHelper. This turns up in the constructor of our FileHelper (for use in the Unit Test)
                mock.Mock<IProcessorLocator>().Setup(loc => loc.GetProcessor<IConfigurationHelper>()).Returns(testMoqConfigurationHelper);
                FileHelper sut = mock.Create<FileHelper>();

                // Act
                List<string> directoryList = sut.GetFilesForPathAsList(testMoqConfigurationHelper.GetConfigurationSetting(SharedTestValues.DesktopTestAppSettingKey));

                // Assert
                Assert.IsTrue(sut.ProcessFiles(directoryList));
                Assert.IsFalse(Directory.GetFiles(testTxtFilesPath).Any(file => !Path.GetExtension(file).Equals(".txt")));
                Assert.IsFalse(Directory.GetFiles(testSqlFilesPath).Any(file => !Path.GetExtension(file).Equals(".sql")));
            }
        }

        #endregion Public Static Test Methods

        #region Test Class Cleanup Logic

        /// <summary>
        ///  
        /// </summary>
        [ClassCleanup]
        public static void CleanupTestResources()
        {
            // Remove traces of test files, for our next run (as this is all plonked in the debug/bin folder, not what you'd want for a genuine test setup most likely)
            Directory.GetFiles(testTxtFilesPath).ToList().ForEach
                (
                    file => 
                    {
                        File.Delete(file);
                    }
                );

            Directory.GetFiles(testSqlFilesPath).ToList().ForEach
                (
                    file => 
                    {
                        File.Delete(file);
                    }
                );

            Directory.GetFiles(testDesktopPath).ToList().ForEach
                (
                    file => 
                    {
                        File.Delete(file);
                    }
                );

            // Remove any test directories created for any run Unit Tests
            Directory.Delete(Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder, SharedTestValues.TestTxtFilesFolder));
            Directory.Delete(Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder, SharedTestValues.TestSqlFilesFolder));
            Directory.Delete(Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder));
        }

        #endregion Test Class Cleanup Logic
    }
}
using System;
using System.IO;

namespace DesktopCleaner.UnitTests.Helpers
{
    /// <summary>
    /// Public static class that holds all of the 
    /// </summary>
    public static class SharedTestValues
    {
        #region Private Static Data Fields

        /// <summary>
        /// Private static data field that (poorly named really) gets access
        /// to the current directory for this application (for our purposes, during debugging, this
        /// will be the bin/debug folder, for demonstration only).
        /// </summary>
        private static Lazy<string> debugPath = new Lazy<string>(() => Directory.GetCurrentDirectory());

        #endregion Private Static Data Fields

        #region Public Constants

        /// <summary>
        /// Public constant that denotes the desktop path
        /// mock up AppSetting key (not actually real, faked
        /// by our MoqConfigurationHelper).
        /// </summary>
        public const string DesktopTestAppSettingKey = "DesktopPath";

        /// <summary>
        /// Public constant that denotes the desktop folder name 
        /// to use during Unit Testing.
        /// </summary>
        public const string TestDesktopFolder = "Test_Desktop";

        /// <summary>
        /// Public constant that denotes the text file folder name 
        /// to use during Unit Testing.
        /// </summary>
        public const string TestTxtFilesFolder = "Txt_Files";

        /// <summary>
        /// Public constant that denotes the sql file folder name 
        /// to use during Unit Testing.
        /// </summary>
        public const string TestSqlFilesFolder = "Sql_Files";

        /// <summary>
        /// Public constant that denotes the name of the first, test sql file 
        /// to use during Unit Testing.
        /// </summary>
        public const string TestSqlFileNameOne = "Test_Sql_File_One.sql";

        /// <summary>
        /// Public constant that denotes the name of the second, test sql file 
        /// to use during Unit Testing.
        /// </summary>
        public const string TestSqlFileNameTwo = "Test_Sql_File_Two.sql";

        /// <summary>
        /// Public constant that denotes the name of the first, test text file 
        /// to use during Unit Testing.
        /// </summary>
        public const string TestTxtFileNameOne = "Test_Txt_File_One.txt";

        /// <summary>
        /// Public constant that denotes the name of the second, test text file 
        /// to use during Unit Testing. 
        /// </summary>
        public const string TestTxtFileNameTwo = "Test_Txt_File_Two.txt";

        #endregion Public Constants

        #region Public Static Properties

        /// <summary>
        /// Gets access (static) to the lazy debugPath.value.
        /// </summary>
        public static string DebugPath
        {
            get
            {
                return debugPath.Value;
            }
        }

        #endregion Public Static Properties
    }
}
using DesktopCleaner.Interfaces;
using DesktopCleaner.UnitTests.Helpers;
using System.Collections.Specialized;
using System.IO;
using System.Linq;

namespace DesktopCleaner.UnitTests.MoqObject
{
    /// <summary>
    /// MoqConfigurationHelper class to provide a specific implementation of an
    /// IConfigurationHelper just for Unit Testing (not necessarily how best to structure
    /// a class, just for illustration purposes only).
    /// </summary>
    public class MoqConfigurationHelper : IConfigurationHelper
    {
        #region Private Static Data Fields

        /// <summary>
        /// Private static data field that represents a mock
        /// set of Application Settings for use during Unit Testing.
        /// </summary>
        private static NameValueCollection testAppSettingsCollection = null;

        #endregion Private Static Data Fields

        #region Constructor

        /// <summary>
        /// Initialises a new instance of a MoqConfigurationHelper.
        /// </summary>
        public MoqConfigurationHelper()
        {
            // THIS COULD, OF COURSE, BE STORED IN AN APP.CONFIG ALSO AS PART OF THIS PROJECT, BUT I WANT TO DEMONSTRATE A FULL MOCK UP HERE AND FANCY DOING A BIT MORE HARD WORK!

            // Set testAppSetingsCollection to be a new NameValueCollection
            testAppSettingsCollection = new NameValueCollection();

            // Create three, mock 'AppSettings' denoting a desktop, sql and text files path (to be used during Unit Tests)
            testAppSettingsCollection.Add(SharedTestValues.DesktopTestAppSettingKey, Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder));
            testAppSettingsCollection.Add("Sql", Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder, SharedTestValues.TestSqlFilesFolder));
            testAppSettingsCollection.Add("Txt", Path.Combine(SharedTestValues.DebugPath, SharedTestValues.TestDesktopFolder, SharedTestValues.TestTxtFilesFolder));
        }

        #endregion Constructor

        #region Public Expression Bodied Methods

        /// <summary>
        /// Public method that returns all 'AppSettings'
        /// (mock only) to the caller.
        /// </summary>
        /// <returns></returns>
        public NameValueCollection GetAllConfigurationSettings() => testAppSettingsCollection;

        /// <summary>
        /// Public method that returns a specified AppSetting
        /// to the caller based on key (mock only).
        /// </summary>
        /// <param name="key">The unique key for the value to be retrieved.</param>
        /// <returns>The value corresponding to the unique key.</returns>
        public string GetConfigurationSetting(string key) => testAppSettingsCollection.GetValues(key).FirstOrDefault();

        #endregion Public Expression Bodied Methods
    }
}

Being a stickler for providing full details, here is the class diagram for the Unit Test project:

Desktop Cleaner unit test project class diagram illustrating structure.

Desktop Cleaner Unit Test Project Class Diagram.

As a final thought, here’s a little bit of proof captured at runtime showing the different concrete implementations retrieved when hitting a breakpoint during debug of the application running in and out of a unit testing scenario:

Illustration showing the IConfigurationHelper object type during debug.

IConfigurationHelper Object Type During Debug.

Illustration showing the IConfigurationHelper object type during unit testing.

IConfigurationHelper Object Type During Unit Testing.

Since generating content for this post I’ve had more thoughts and ideas surrounding DI in general, something that seems to make a follow-up post a worthy thing to pursue! I’d like to flesh these examples out at the very least, so watch this space for more on this subject.

Thanks again all, until the next time…