A pleasant walk through computing

Comment for me? Send an email. I might even update the post!

Catching Up on Coding - TDD Part 2

I’ve been a software developer for twenty years, but am behind in some skills. This series chronicles my self-improvement.

Taking a cue from the 70s and its badass fonts, my Fantastic Journey is traveling from skill to skill, trying to escape every software engineer’s Bermuda Triangle: obsolescence. I don’t have Jared Martin’s Sonic Energizer to focus my thoughts and manipulate matter. All I can do is listen to the groovy theme music.

Previously on CUOC: TDD Part 1
Next Episode: TDD Part 3

 

 

Teaser

It’s one thing to practice TDD from the start. It’s another to take legacy code that you wrote and create unit tests for it. My EduAgent project includes a client service that processes requests to update the registry.

Looking at my code, I right away see my first stumbling block: the purpose of the code is changing the registry. For testing, this means:

  • Affecting the registry of whatever computer the tests run on.
  • Guaranteeing each test starts with a clean environment. What does this mean for parallel testing?
  • Guaranteeing the registry returns to its original state, regardless of test results.
  • Not breaking the computer.

These are characteristics of integration/functional tests, not unit tests. Should I mock the registry classes to deal with this code?

object value = Registry.GetValue(keyName, valueName, null);

If I do—if I can—am I really testing anything? Or am I creating fake conditions that assure the test will pass? There’s a danger, in unit testing, of creating tests that don’t actually test the method: they “test” a mock that will always return the expected value.

Act 1 – What I Can Test, What I Should

The purpose of mocks is to allow the unit test to focus on what it can test, and ignore what can corrupt the test—assuming what can corrupts the test isn’t exactly what should be tested!

A classic, challenging example is methods that access a database. I don’t want to test if I can access the database. I want to test what I’m doing with the data. For example, consider this class method.

public class EmployeeInfoService
{
    IEmployeeDbContext _db;
    public EmployeeInfoService(IEmployeeDbContext db) { _db = db; }
    public List GetAverageHourlyPay(int[] employeeIds)
    {
        return from stats in _db.PayStubs
        //...a bunch of code that gets data and calculates the hourly pay by doing this:
                // stats.Hours / stats.Amount
        ;
    }
}

I don’t care, in the test I’m about to write, if I can access the database, or if the database is returning the right data, or breaks when I hand it a list of EmployeeIds. All I care about is whether the method properly does the math given specific numbers. So, I’d mock the EmployeeDbContext and fabricate the numbers.

 [Fact]
    public void EmployeeInfoService_GetAverageHourlyPay_Should_Correctly_Calculate()
    {
        var db = new MockEmployeeDbContext();
        //...add a bunch of test data to the mock, then pass it to service
        var service = new EmployeeInfoService(db);
        var list = service.GetAverageHourlyPay(new int[] { 1, 2, 3 });
        Assert.Equals(23.34, list[0].AverageHourlyPay);
        Assert.Equals(17.98, list[1].AverageHourlyPay);
    }

Contrast that to this method.

    public string[] GetEmployeeNames()
    {      return _db.Employees.Select(a => a.Name).ToArray();
    }

Is there any reason to create a unit test for this method? I don’t think so. The test would look something like this.

    [Fact]
    public void EmployeeInfoService_GetEmployeeNames_Should_Return_A_List_Of_Names()
    {
        var db = new MockEmployeeDbContext();
        //...add a bunch of mock Employees with names, then pass to service
        var service = new EmployeeInfoService(db);
        var list = service.GetEmployeeNames();
        Assert.True(list.Contains("Varian"));
    }

This gets us nothing. All we did was test that our mocking framework works. So…

Lesson 1: Be sure you’re testing something that can fail.

Act 2 – The Simple Test

For my RegistryService class, I have a different problem as stated above. Can I even mock the .Net Registry class? We’ll look at that shortly. For right now, I’ll evaluate all the methods and see which ones I can test without mocking. Here’s the complete list:

  • ProcessRequest
  • GetRegistryKeyValue
  • GetRegistryValueKind
  • SetRegistryKeyValue
  • DeleteRegistryKey
  • DeleteRegistryValue
  • OpenSubKey64
  • ParseRegistryHive
  • NotifyAppsOfRegistryChange

Of all these, just one doesn’t require using registry data: ParseRegistryHive. The method’s purpose is to return the hive enum given a string.

        public static RegistryHive ParseRegistryHive(string hiveName)
        {
            if (hiveName.ToUpper() == "HKEY_CLASSES_ROOT") { return RegistryHive.ClassesRoot; }
            else if (hiveName.ToUpper() == "HKEY_CURRENT_USER") { return RegistryHive.CurrentUser; }
            else if (hiveName.ToUpper() == "HKEY_LOCAL_MACHINE") { return RegistryHive.LocalMachine; }
            else if (hiveName.ToUpper() == "HKEY_USERS") { return RegistryHive.Users; }
            else if (hiveName.ToUpper() == "HKEY_CURRENT_CONFIG") { return RegistryHive.CurrentConfig; }
            //last chance, will throw error if invalid
            else return (RegistryHive)Enum.Parse(typeof(RegistryHive), hiveName);
        }

I’m using xUnit.net for my unit testing. xUnit’s Theories are pretty nice, allowing testing sets of data. My tests verify that the method throws errors—or doesn’t—appropriately, and also that it returns the correct hive. I wrote a note to myself about that last one, summed up as:

Lesson 2: Don’t copy/paste any code from your test into the method you’re testing. What if your test has a bug?

    public class RegistryService_ParseRegistryHive_Should
    {
        [Theory]
        [InlineData("HKEY_CLASSES_ROOT")]
        [InlineData("HKEY_CURRENT_USER")]
        [InlineData("HKEY_LOCAL_MACHINE")]
        [InlineData("HKEY_USERS")]
        [InlineData("HKEY_CURRENT_CONFIG")]
        [InlineData("hkey_current_config")]
        public void NotThrowErrorWithValidHive(string name)
        {
            var hive = RegistryService.ParseRegistryHive(name);
        }

        [Theory]
        [InlineData("HKEY_CLASSES_ROOT")]
        [InlineData("HKEY_CURRENT_USER")]
        [InlineData("HKEY_LOCAL_MACHINE")]
        [InlineData("HKEY_USERS")]
        [InlineData("HKEY_CURRENT_CONFIG")]
        public void ReturnCorrectEnumWithValidHive(string name)
        {
            //This basically reproduces the method code. Need to NOT copy/paste from method, but
            //instead rewrite. In TDD, would NOT copy/paste from the test, otherwise there's a danger
            //the test duplicates a wrong condition.
            var hive = RegistryService.ParseRegistryHive(name);
            switch (name)
            {
                case "HKEY_CLASSES_ROOT":
                    Assert.True(hive == Microsoft.Win32.RegistryHive.ClassesRoot);
                    break;
                case "HKEY_CURRENT_USER":
                    Assert.True(hive == Microsoft.Win32.RegistryHive.CurrentUser);
                    break;
                case "HKEY_LOCAL_MACHINE":
                    Assert.True(hive == Microsoft.Win32.RegistryHive.LocalMachine);
                    break;
                case "HKEY_USERS":
                    Assert.True(hive == Microsoft.Win32.RegistryHive.Users);
                    break;
                case "HKEY_CURRENT_CONFIG":
                    Assert.True(hive == Microsoft.Win32.RegistryHive.CurrentConfig);
                    break;
                default:
                    Assert.True(false,name + " didn't return a valid hive. Hive enum returned was " + hive);
                    break;
            }
        }

        [Theory]
        [InlineData("fail")]
        [InlineData("")]
        public void ThrowErrorWithInvalidHive(string name)
        {
            Assert.Throws(() =>  RegistryService.ParseRegistryHive(name));
        }
    }

Act 3 – Testing the Difficult: Mock it, or . . .

I’ve been putting it off long enough. What about the rest of the methods? You know, the ones that could completely screw up my registry?

First, which methods do testable work? Some of them are just wrappers so that I can get back a better error message, for example:

        public static void SetRegistryKeyValue(string keyName, string valueName, string value, RegistryValueKind dataType = RegistryValueKind.String)
        {
            try
            {
                Registry.SetValue(keyName, valueName, value, dataType);
            }
            catch (Exception ex)
            {
                throw new Exception("Error setting registry value keyName '" + keyName + "', valueName '" + valueName + ", value '" + value + "'\r\n" + ex.GetBaseException().Message);
            }
        }

Do I need to test this? Well, I’d like to test that I get back the right exception, so…hmm. OK, let’s see if anyone has mocked the registry.

In the last bullet, I quote from an excellent Stack Overflow response on the subject. In fact, here are two comments.

The research tells me I have two choices:

  1. Mock the concrete Registry class
  2. Use a wrapper around the Registry class

I looked at the Prig example. Whew! That’s a lot of setup! And I’m not prepared to pay for TypeMock or JustMock, though I expect they’re excellent.

This means wrapping the Registry class. Before I try out SystemWrapper, I’m going to create my own wrapper. I want to understand what’s involved. (This is self-education, after all!) The methods I’m using are:

Registry.GetValue
Registry.SetValue
RegistryKey.GetValueKind
RegistryKey.DeleteSubKey
RegistryKey.DeleteValue
RegistryKey.OpenBaseKey
RegistryKey.OpenBaseKey.OpenSubKey

All right, boys! Wrap…That…Code!!!

I had to rethink my whole approach to my RegistryService class, which consumes the Microsoft.Win32.Registry. Originally I wrote it as a static class, since it didn’t need to be instantiated. But this class now could depend on different “registry providers.” I want to protect the class from being misused. A static SetRegistryProvider method won’t work, because of the danger that in production one caller sets it one way and another sets it differently. It’s the same as if a class could use more than one database back end; you wouldn’t make it static. The solution was to remove static, and make the class entirely instance-able.

Moving on, the Registry wrapper is pretty straight forward. The oddity is that I’m wrapping a static class in an instance.

    public interface IRegistryWrapper
    {
        object GetValue(string keyName, string valueName, object defaultValue);
        void SetValue(string keyName, string valueName, object value, RegistryValueKind valueKind);
    }

    public class RegistryWrapper : IRegistryWrapper
    {
        public object GetValue(string keyName, string valueName, object defaultValue)
        {
            return Registry.GetValue(keyName, valueName, defaultValue);
        }

        public void SetValue(string keyName, string valueName, object value, RegistryValueKind valueKind)
        {
            Registry.SetValue(keyName, valueName, value, valueKind);
        }
    }

The RegistryKey wrapper presented a challenge. The constructor for RegistryKey is private. You cannot create an instance of RegistryKey this way:

RegistryKey key = new RegistryKey(); //this won't compile

Instead, instances are created using the static method OpenBaseKey().

RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);

My abstraction needs to be clear, I want to create an interface, but interfaces can’t have static members.

A base key is required for RegistryKey to function, therefore it’s required for my wrapper to function. But the RegistryService class, which uses RegistryKey, encapsulates which base key will be used; each method could instantiate its own RegistryKey with different base keys. For example:

public void DeletePluginVersionValue(string id)
{
    //_registryKey was injected via the constructor
    RegistryKey basekey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default);
    using (RegistryKey key = basekey.OpenSubKey(@"SOFTWARE\EduAgent\RegistryPlugin", false))
    {
        key.DeleteValue("Value");
        key.Close();
    }
}

My abstracted class is going to work similarly.

public void DeletePluginVersionValue(string id)
{
    //_registryKey was injected via the constructor
    IRegistryKeyWrapper basekey = _registryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default);
    using (IRegistryKeyWrapper key = basekey.OpenSubKey(@"SOFTWARE\EduAgent\RegistryPlugin",false))
    {
        key.DeleteValue("Value");
        key.Close();
    }
}

But for testing, I need to pass in a non-null class instance that implements an interface, but does not have a base class yet. I can’t do this:

    public interface IRegistryKeyWrapper: IDisposable
    {
        IRegistryKeyWrapper OpenSubKey(string name, bool writable);
        //originally static
        IRegistryKeyWrapper OpenBaseKey(RegistryHive hKey, RegistryView view);
    }

    public class RegistryKeyWrapper : IRegistryKeyWrapper
    {
        private RegistryKey _baseKey;
        private RegistryKeyWrapper(RegistryKey key)
        {
            _baseKey = key;
        }
        //etc.

Why not? Follow along.

The RegistryService constructor:

    public class RegistryService
    {
        private IRegistryWrapper _registry;
        private IRegistryKeyWrapper _registryKey;

        public RegistryService(IRegistryWrapper registry, IRegistryKeyWrapper key)
        {
            _registry = registry;
            _registryKey = key;
        }

Using the RegistryService:

//this won't compile; RegistryKeyWrapper requires base key!
RegistryService service = new RegistryService(new RegistryWrapper(), new RegistryKeyWrapper());

I need to be able to create a new RegistryKeyWrapper(), but my live registry wrapper right now requires an actual registry base key. The (unfortunate) solution is to allow the user to create an instance of the class that can’t work.

    public class RegistryKeyWrapper : IRegistryKeyWrapper
    {
        private RegistryKey _baseKey;

        /// 
        /// Note the class can't be used until instantiated using OpenBaseKey or setting to another RegistryKeyWrapper.
        /// This constructor is here to allow an instance to be passed via dependency injection.
        /// 
        public RegistryKeyWrapper() { }

        private RegistryKeyWrapper(RegistryKey key)
        {
            _baseKey = key;
        }

In the RegistryService example, above, if the user were to use _registryKey immediately, without setting it using OpeBaseKey, it would fail because the private variable _baseKey has not been set.

I wouldn’t call this ideal, but it does allow us to test the class.

EDIT 8/31/16
-------------------------------------------------------------

Not only is it not ideal, but it’s not even good. What I’m trying to do is wrap RegistryKey in a pass-through manner. But that’s a mistake, because it implements IDisposable and in my wrapper I should not implement IDisposable.

In a later post, I’ll explain how I rewrote my RegistryKey wrapper in a better way. It doesn’t affect the validity of the info in this post.

-------------------------------------------------------------

First, I’ll fix up my previous tests for ParseRegistryHive that relied on Registry. In my unit test project I create the mock classes. At this point, I don’t even make the classes work, since ParseRegistryHive doesn’t depend on any methods.

    class RegistryMock : IRegistryWrapper
    {
        public object GetValue(string keyName, string valueName, object defaultValue)
        {
            throw new NotImplementedException();
        }

        public void SetValue(string keyName, string valueName, object value, RegistryValueKind valueKind)
        {
            throw new NotImplementedException();
        }
    }

And update a test to use the new service, passing in the mocks.

        IRegistryWrapper _registry = new RegistryMock();
        IRegistryKeyWrapper _registryKey = new RegistryKeyMock();
                
        [Theory]
        [InlineData("HKEY_CLASSES_ROOT")]
        [InlineData("HKEY_CURRENT_USER")]
        [InlineData("HKEY_LOCAL_MACHINE")]
        [InlineData("HKEY_USERS")]
        [InlineData("HKEY_CURRENT_CONFIG")]
        [InlineData("hkey_current_config")]
        public void NotThrowErrorWithValidHive(string name)
        {
            var service = new RegistryService(_registry, _registryKey);
            var hive = service.ParseRegistryHive(name);
        }

Now, create a test for the RegistryMock.

    public class RegistryService_GetRegistryKeyValue_Should
    {
        IRegistryWrapper _registry = new RegistryMock();
        IRegistryKeyWrapper _registryKey = new RegistryKeyMock();

        [Fact]
        public void ReturnNullConstantTextIfValueIsMissing()
        {
            var service = new RegistryService(_registry, _registryKey);
            var result = service.GetRegistryKeyValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\EduAgent", "Version");
            Assert.Equal(result, service.NoValue);
        }
    }

Which requires RegistryMock.GetValue to be implemented:

    class RegistryMock : IRegistryWrapper
    {
        public object GetValue(string keyName, string valueName, object defaultValue)
        {
            //this may become cumbersome, but for now specify some return values
            switch (keyName)
            {
                case @"HKEY_LOCAL_MACHINE\SOFTWARE\EduAgent":
                    if (valueName == "Version") return defaultValue;
                    break;
            }
            throw new Exception("Invalid keyName");
        }

Running the test, it passes.

Next up, using the RegistryKeyMock. Here’s the test:

    public class RegistryService_OpenSubKey64_Should
    {
        IRegistryWrapper _registry = new RegistryMock();
        IRegistryKeyWrapper _registryKey = new RegistryKeyMock();

        [Fact]
        public void ThrowExceptionWhenUsingInvalidKey()
        {
            var service = new RegistryService(_registry, _registryKey);
            var ex = Assert.Throws(() => service.OpenSubKey64(@"HKEY_LOCAL_MACHINE\SOFTWARE\EduAgentMissing"));
            Assert.Equal("Error opening subkey 'HKEY_LOCAL_MACHINE\\SOFTWARE\\EduAgentMissing'. Operation returned null.", ex.Message);
        }
    }

Here are the relevant methods I had to implement. This one was kind of tricky because I have to set properties that are read only. I’m making use of the latest C# language features to set the value of read only properties in the constructor. I also needed a helper method to return the string representation of a hive name.

    public class RegistryKeyMock : IRegistryKeyWrapper
    {
        public RegistryKeyMock() { }
        public RegistryKeyMock(string name, int subKeyCount, int valueCount, RegistryView view)
        {
            Name = name;
            SubKeyCount = subKeyCount;
            ValueCount = valueCount;
            View = view;
        }

        public string Name { get; }
        public int SubKeyCount { get; }
        public int ValueCount { get; }
        public RegistryView View { get; }

        public IRegistryKeyWrapper OpenBaseKey(RegistryHive hKey, RegistryView view)
        {
            return new RegistryKeyMock(HiveToString(hKey), 10, 10, view);
        }

        public IRegistryKeyWrapper OpenSubKey(string name, bool writable)
        {
            if (name == @"SOFTWARE\EduAgentMissing")
                return null;
            return new RegistryKeyMock(Name + "\\" + name, SubKeyCount, ValueCount, View);
        }

        private string HiveToString(RegistryHive hive)
        {
            string key = "HKEY_";
            if (hive == RegistryHive.ClassesRoot) return key + "CLASSES_ROOT";
            if (hive == RegistryHive.CurrentConfig) return key + "CURRENT_CONFIG";
            if (hive == RegistryHive.CurrentUser) return key + "CURRENT_USER";
            if (hive == RegistryHive.LocalMachine) return key + "LOCAL_MACHINE";
            if (hive == RegistryHive.Users) return key + "USERS";
            return "";
        }
    }

Test it, it passes, love those green lights!

Tag

This was like a special made-for-TV movie of Fantastic Journey. With all the stuff I’ve done, what haven’t I? Well, there are two big ones:

But I’m leaving those for a future post. Otherwise, like our intrepid explorers, I’ll be canceled and never get back to my own time and place.

Catching Up on Coding - TDD Part 1

I’ve been a software developer for twenty years, but am behind in some skills. This series chronicles my self-improvement.

There are some pretty high-tech tools out there, but nothing that matches the inspiration provided in the 70s TV show “Search” (originally “Probe”). I don’t have Burgess Meredith, a Probe Scanner or a catchy theme song to help me out, so, like Hugh O’Brian, I’ll have to rely on my wits and Test Driven Development (TDD).

Previously, on CUOC: The Syllabus.
Next Episode: TDD Part 2

 

Teaser

I’m not truly new to TDD. I wrote a (not very good) unit testing framework for Visual Basic 6 back in 2000. I’ve used TDD in professional projects. But now it’s time to make it a habit. To do that, I need a crash coarse, then retrofit my EduAgent code (applying “Test Eventually Development”) before writing new code.

Act 1 – The Elemental Education

Let’s give primary credit where it’s due. I read James Bender’s blog 30 Days of TDD. Bender’s series is very good overall. He does—frustratingly--have sloppy grammar and punctuation errors in every post. But his information is otherwise clear and solid. In fact, his description of SOLID is one of the best I’ve read. Thanks, James!

But first things first: what problem was TDD trying to solve?

Programmers, being human, don’t like to test our work. Most of us find it as hard as writers self-editing or composers checking for wrong notes. We like QA departments because they find our (careless) mistakes for us. We pretend to hate QA, because we pretend we’re egotistical Greek gods incapable of flaw.

Unit testing frameworks allowed testing the public interface of our classes. But that wasn’t enough. Kent Beck encouraged an upside-down approach to writing code, where we write a failing test first, then make it pass. This naturally builds up a library of tests that can be run quickly, reducing the chance of new features breaking the application, and building developer confidence. It also turned out that creating easily testable methods led to generally more maintainable code. Thus, some people revised TDD to mean test-driven design.

What are the elements of TDD? What’s needed to build testable code?

Elements

  • Test framework such as NUnit and xUnit.net
  • Test runner, for executing tests and viewing results.
  • Dependency Inversion (depend on abstractions) and Dependency Injection (decouple dependencies). Both are covered pretty well in this article.
  • Mocking (control results from external resources, such as databases)
  • Refactoring (improving code maintainability without changing the public interface)

Act 2 – Some Code, a Test

Here’s a simple example of TDD, creating code that needs to be tested, and problems with it. I’m using xUnit.Net because I’ve always liked it. I won’t go into how to set up your environment; you can learn that at Getting Started with xUnit.net. However, I do have three tips for using the VS Test Runner (which you open via Test > Windows > Test Explorer).

  • Tear off the Test Explorer into its own window, so that you can easily resize and see all the tests.
    image

  • Group the test results by class
    image

  • In your unit test project, add an app.config file with the following setting. This causes the result to display only the method name instead of the fully qualified name.

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="xunit.methodDisplay" value="method"/>
      </appSettings>
    </configuration>
    

Our contrived application helps teachers grade coursework. We’re writing a class dealing with the coursework, and we’re consuming a third-party service—GradeMark—that returns a grade. One challenge, however, is we don’t control the grade that GradeMark returns given a set of scores. It depends on however the school has configured it. So, today 90% or higher could be an “A,” but tomorrow 93% or higher could be an “A.”

Our CourseWork class will have two methods. One that returns a percentage, and the other that returns a grade message. The grade in the message will come from the GradeMark “service,” and we’ll eventually have to mock that service.

First, in CourseWork, create a GetPercent function that doesn’t work. We want a failing test.

    public class CourseWork
    {
        public decimal GetPercent(decimal actual, decimal maximum)
        {
            throw new NotImplementedException();
        }
    }

In the unit tests project, create the test. Notice the naming convention I’m using along with nested classes; this will help make the test results readable. There are lots of naming conventions out there. Consistency and clarity are the big deals.

Our first test checks that we get back a percent in a particular format. We want “a hundred percent” to return as 100.00.

    public class BasicTdd
    {
        public class CourseWork_GetPercent_Should
        {
            [Fact]
            public void Return100PercentAs100PointZero()
            {
                var cw = new CourseWork();
                decimal percent = cw.GetPercent(100, 100);
                Assert.Equal(100m, percent);
            }
        }
    }

Run it and it fails.

image

Write enough code for the test to pass.

        public decimal GetPercent(decimal actual, decimal maximum)
        {
            decimal result = (actual / maximum) * 100m;
            return result;
        }

Run the test and it passes.

image

Our next test will check if the result is rounded. This does not depend on the first test; they could be run in reverse order.

    public class BasicTdd
    {
        public class CourseWork_GetPercent_Should
        {
            [Fact]
            public void RoundPercentToTwoDecimalPlaces()
            {
                var cw = new CourseWork();
                var percent = cw.GetPercent(1, 7);
                var roundedPercent = Math.Round(percent, 2);
                Assert.Equal(roundedPercent, percent);
            }
        }
    }

Run it, and it fails.

image

Update the code to make it pass.

        public decimal GetPercent(decimal actual, decimal maximum)
        {
            decimal result = Math.Round((actual / maximum) * 100m,2);
            return result;
        }

image

That’s enough to demonstrate a basic test. Now, on to something that will require mocking.

Act 3 – Mocu-mental Grades

Let’s create a class that represents our fictional third-party service, GradeMark. Remember, it returns a grade when supplied a percent, but we can’t depend on what that grade will be. For our dummy service, we won’t even use the percent parameter.

    public class GradeMarkService
    {
        public string GetGrade(decimal percent)
        {
            var rnd = new Random();
            int code = rnd.Next(65, 70);
            return ((char)code).ToString();
        }
    }

We’re just returning a random letter A-D (no failures in our courses!). Back in our CourseWork class, we’ll start a function that returns a grade, and write a test for it that will fail. Here’s the test.

        public class CourseWork_GetGradeMessage_Should
        {
            [Fact]
            public void ReturnTheCorrectlyFormattedMessage()
            {
                var cw = new CourseWork();
                string msg = cw.GetGradeMessage(4, 15); //these values don't matter
                string expected = "The grade is B";
                Assert.Equal(expected, msg);
            }
        }

What we’re testing is getting the expected message text. We’re not testing if GetPercent works, and we’re not testing if the GradeMark service works. When we run the test, it fails, so we write this code to try to make it pass. Some people would say that we shouldn’t bother with the GradeMark service yet, but let’s assume we’re at that point.

        public string GetGradeMessage(decimal actual, decimal maximum)
        {
            var service = new GradeMarkService();
            return "The grade is " + service.GetGrade(GetPercent(actual, maximum));
        }

We got lucky; it failed. But, remember, we can’t guarantee what letter grade will be returned. It could have passed. Run the tests enough times and it will pass.

image

Our GetGradeMessage function has a dependency on the GradeMark service, and is tightly coupled to it. We need to loosely couple that dependency by injecting it. We could do that at the method level, like this:

        public string GetGradeMessage(decimal actual, decimal maximum, GradeMarkService gradeService)
        {
            return "The grade is " + gradeService.GetGrade(GetPercent(actual, maximum));
        }

But, typically, a service like this is consumed by the class. So, we’ll inject it in the class’s constructor.

    public class CourseWork
    {
        GradeMarkService _gradeService;

        public CourseWork(GradeMarkService gradeService)
        {
            _gradeService = gradeService;
        }

        public string GetGradeMessage(decimal actual, decimal maximum)
        {
            return "The grade is " + _gradeService.GetGrade(GetPercent(actual, maximum));
        }

Great, but that doesn’t really help us, does it? We still need a GradeMarkService to pass in during our test, and control the letter grade it returns. Using some mocking frameworks, it’s possible to mock a legacy object. But in this case, we’re hoping for one of two things from our vendor to make our lives easier.

An Interface

Ideally, our vendor has programmed to an interface, using the Dependency Inversion Principle. We’ll simulate that in our fictional service class.

    public interface IGrader
    {
        string GetGrade(decimal percent);
    }

    public class GradeMarkService: IGrader
    {
        public string GetGrade(decimal percent)
        {
            var rnd = new Random();
            int code = rnd.Next(65, 70);
            return ((char)code).ToString();
        }
    }

Next, we update our class to inject the interface we’re testing, instead of the concrete instance.

    public class CourseWork
    {   IGrader _gradeService;

        public CourseWork(IGrader gradeService)
        {
            _gradeService = gradeService;
        }

Our class is now ready for testing. We don’t need the GradeMarkService. We just need our own mock class implementing the required interface. Back in our test project, we’ll create that.

    public class GradeMarkServiceMock: IGrader
    {
        public string GetGrade(decimal percent)
        {
            return "B";
        }
    }

And, update our tests to accept the mock object.

            [Fact]
            public void Return100PercentAs100PointZero()
            {
                var cw = new CourseWork(new GradeMarkServiceMock());
                decimal percent = cw.GetPercent(1, 1);
                Assert.Equal(100m, percent);
            }
            [Fact]
            public void RoundPercentToTwoDecimalPlaces()
            {
                var cw = new CourseWork(new GradeMarkServiceMock());
                var percent = cw.GetPercent(1, 7);
                var roundedPercent = Math.Round(percent, 2);
                Assert.Equal(roundedPercent, percent);
            }
        }

        public class CourseWork_GetGradeMessage_Should
        {
            [Fact]
            public void ReturnTheCorrectlyFormattedMessage()
            {
                var cw = new CourseWork(new GradeMarkServiceMock());
                string msg = cw.GetGradeMessage(4, 15); //these values don't matter
                string expected = "The grade is B";
                Assert.Equal(expected, msg);
            }
        }

When we run our tests a few times, the GetGradeMessage test passes consistently.

An overridable class

Our vendor could also have made the GetGrade method overridable. In that case, we’d create a mock object, override GetGrade, and always return “B”. But with a significant object, there could be many problems doing that. It’s best if we can program against interfaces, because that way*  we don’t have to use the original classes at all*.

What’s a real-world example? What about a shipping service that our application uses to calculate shipping rates? Several problems could exist in consuming that service instead of mocking it:

  • It could be very slow to use that service in our tests.
  • It could return inconsistent results that affect our tests.
  • We might get charged every time we use the service.

Databases are another example. Testing against a database is difficult because you want the data to always start in a consistent state. Database tests are slow. They are better left for integration tests.

Refactoring

The last step in TDD is making the code better, and also making the tests better. For example, we get an instance of the CourseWork class repeatedly. We can declare that as a class field. xUnit creates a new instance of the class for each test, so it will will always be a new instance of CourseWork.

    public class BasicTdd
    {
        public class CourseWork_GetPercent_Should
        {
            public CourseWork _cw = new CourseWork(new GradeMarkServiceMock());

            [Fact]
            public void Return100PercentAs100PointZero()
            {
                decimal percent = _cw.GetPercent(1, 1);
                Assert.Equal(100m, percent);
            }
            [Fact]
            public void RoundPercentToTwoDecimalPlaces()
            {
                var percent = _cw.GetPercent(1, 7);
                var roundedPercent = Math.Round(percent, 2);
                Assert.Equal(roundedPercent, percent);
            }
        }

        public class CourseWork_GetGradeMessage_Should
        {
            public CourseWork _cw = new CourseWork(new GradeMarkServiceMock());

            [Fact]
            public void ReturnTheCorrectlyFormattedMessage()
            {
                string msg = _cw.GetGradeMessage(4, 15); //these values don't matter
                string expected = "The grade is B";
                Assert.Equal(expected, msg);
            }
        }
    }

Of course, rerun the tests and make sure they pass!

Tag

Test-driven development isn’t natural at first. But it’s got a rat-hits-food-lever pleasure I can’t deny. Kind of like having Probe Control’s Angel Tompkins whispering in my ear.

References

30 Days of TDD

Getting Started with xUnit.net

xUnit: display only method name

xUnit: Shared Context Between Tests

7 Popular Unit Test Naming Conventions

Naming standards for unit tests

An Absolute Beginner's Tutorial on Dependency Inversion Principle

Writing to the Current User(s) Registry When Running as System

In a project I’m working on, I need to change the Group Policy Object (GPO) registry settings, both for the computer and for the logged in user. Both of these present problems. This article addresses the logged in user scenario.

The actual application is a Windows service running on the client that accepts requests from a remote machine. The complication is that the service will need to run as System so that it can write to any part of the registry.

Below is prototyping and troubleshooting using a Console application.

Goal

Run a Console application as the System user and write to the GPO that restricts running applications. Here’s the GPO if you want to look it up in Group Policy Editor (gpedit.msc).

User Configuration\Administrative Templates\System\Don't run specified Windows applications.

Challenges/Issues

64-bit Windows has both logical and physical registry entries. This is a problem when updating keys that are used by other programs (in this case, Windows itself). You have to be sure you’re updating the right key. The problem really presents itself when writing to the LOCAL_MACHINE hive. The physical location—such as the Wow6432Node key—depends on whether the application is 64 or 32 bits.

The CURRENT_USER hive doesn’t care about 64/32 bits. But remember that a computer can have multiple users logged on. Also, where does the System user’s settings go? Finally, how will we find out who is logged in? What a mess!

Tools and Environment

I’m running Visual Studio 2015 Community on 64-bit Windows 10.

This is the registry key/value we’ll be creating throughout, setting its value to 1.

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\DisallowRun

Test Writing to the Registry

We first need to write to the registry and see the results. Create a Console Application with the following code.

using System;
using Microsoft.Win32;

namespace RegistryPrototyping
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                WriteRegistry();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.GetBaseException().Message);
            }
            Console.WriteLine("Finished. Press any key to close.");
            Console.ReadLine();
        }

        static void WriteRegistry()
        {
            string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer";
            string valueName = "DisallowRun";
            string value = "1";
            RegistryValueKind dataType = RegistryValueKind.DWord;
            Registry.SetValue(keyName, valueName, value, dataType);
        }
    }
}

Run the application. You should get an error

Access to the registry key 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer' is denied.

This is our first problem. Our code needs permissions to write to the registry.

For some developers, this problem will be hidden because they turn off UAC or always run Visual Studio as administrator. I don’t do either of these exactly because I’ll catch some permissions issue early.

The obvious next step is to close our app, open Visual Studio using Run as Administrator, then reopen/run the app.

image

No error, and the key is written to the expected registry key (i.e. the currently logged in user).

image

Great! Next task, testing as Local System.

But first, delete the DisallowRun key!

Testing as Local System

We need to run our app—either the .exe or Visual Studio—as Local System. I didn’t find a built-in Windows way to do this. The recommended method is to use Sysinternals’ psexec utility, which is normally used to execute commands on remote domain machines.

  1. Download psexec.
  2. Open a command prompt As Administrator (you must do this), and navigate to the folder where you extracted psexec.exe.
  3. Launch the desired application with the –i and –s switches. These run the application locally in interactive mode under the System account.

I right-clicked on my Visual Studio icon > Properties to get the path, and ended up with this command.

psexec –i –s “C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe"

When you launch this way, you’re running as if logged in under a different profile, so VS will go through its initial startup prompts.

  1. Open your Console solution; you’ll need to navigate to its location via C:\Users\[username].
  2. Run it. Check your registry key. Where the heck is the new value? Because we’re running as System, the registry value will be written to the .Default user key.

image

Well, heck! This obviously isn’t what we want. We need to write to the currently logged on user’s profile. But this result gives us a clue how we’ll solve our problem later.

Impersonation – False Start

At first, impersonation seems like the way to go. If I can just find out who’s currently logged on and working, I should be able to impersonate that user and write to the registry on that user’s behalf.

There are two problems with this.

  1. What if there are multiple users logged on? How do I find out which user is actively working?
  2. Will I need to run with elevated privileges? (hint: yes, of course)

If there are multiple users logged in, I didn’t find a way to determine who is actively using the computer. That seems like a poor requirement anyway. Don’t I care if, for instance, a scheduled task starts running as the logged in (but not active) user? Yes, because I might want my agent to prohibit it. What if it’s a headless system that’s always logged on? Worse, what if I want to run the client on a Windows server (which allows multiple simultaneous users via RDP)?

But maybe someone more clever than me wants to figure this out. There might be a way by looking at the active desktop(s).

The second problem is, for us, the impractical barrier to overcome. Writing to the registry requires elevation. The way we’d be impersonating the user would be to get a handle to a running process, then impersonating via that handle. But the user will not be running a known-elevated process. So, we’d be stuck. As soon as we tried to write to the registry, it would fail. And if we try to elevate the process (if we even could do that), the user would get prompted, defeating the goal of the program.

But we can still do what we want. After all, as System we can write to most parts of the physical registry.

Writing to the User’s Key

When we wrote to the System user’s logical hive CURRENT_USER, we ended up in the physical hive USERS. That’s where all the user registry settings are. CURRENT_USER is a symbolic link, a redirection for the active user. Here’s my computer’s USERS hive:

image

Those long SIDs are the users. If I can get those, I can write to the user’s Group Policy setting.

Step one, revise the WriteRegistry method.

static void WriteRegistry(string sid)
    {
        string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer";
        string valueName = "DisallowRun";
        string value = "1";
        keyName = keyName.Replace("HKEY_CURRENT_USER", @"HKEY_USERS\" + sid);
        RegistryValueKind dataType = RegistryValueKind.DWord;
        Registry.SetValue(keyName, valueName, value, dataType);
    }

Step two, crazy lots of code!

You’ll need these addtional references.

using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Diagnostics;
using System.Collections.Generic;

Use a Win32 API function to get the logged on users. This is some deeper stuff, and I didn’t write it. The most I did was put it in a class and make the function return all the users.

The meat of this—the cool part—is using Process.GetProcessesByName with an argument of “explorer”. This will return anyone logged on, because explorer is (typically) always running.

class WindowsIdentityHelper
{

    [DllImport("advapi32", SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    static extern int OpenProcessToken(
    System.IntPtr ProcessHandle, // handle to process
    int DesiredAccess, // desired access to process
    ref IntPtr TokenHandle // handle to open access token
    );

    [DllImport("kernel32", SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    static extern bool CloseHandle(IntPtr handle);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
    int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

    public const int TOKEN_ASSIGN_PRIMARY = 0x0001;
    public const int TOKEN_DUPLICATE = 0x0002;
    public const int TOKEN_IMPERSONATE = 0x0004;
    public const int TOKEN_QUERY = 0x0008;
    public const int TOKEN_QUERY_SOURCE = 0x0010;
    public const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
    public const int TOKEN_ADJUST_GROUPS = 0x0040;
    public const int TOKEN_ADJUST_DEFAULT = 0x0080;
    public const int TOKEN_ADJUST_SESSIONID = 0x0100;
    public const int TOKEN_READ = 0x00020000 | TOKEN_QUERY;
    public const int TOKEN_WRITE = 0x00020000 | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT;
    public const int TOKEN_EXECUTE = 0x00020000;

    public static List GetLoggedOnUsers()
    {
        List users = new List();
        string errs = "";
        IntPtr hToken = IntPtr.Zero;
        //Get a process that will always be available.
        foreach (Process proc in Process.GetProcessesByName("explorer"))
        {
            try
            {
                if (OpenProcessToken(proc.Handle,
                TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
                ref hToken) != 0)
                {
                    WindowsIdentity newId = new WindowsIdentity(hToken);
                    CloseHandle(hToken);
                    users.Add(newId);
                }
                else
                {
                    errs += String.Format("OpenProcess Failed {0}, privilege not held\r\n", Marshal.GetLastWin32Error());
                }

            }
            catch (Exception ex)
            {
                errs += String.Format("OpenProcess Failed {0}\r\n", ex.Message);
            }
        }
        if (errs.Length > 0) { throw new Exception(errs); }
        return users;
    }

And a method to write to the users’ registries.

static void WriteToLoggedOnUsers()
{
    foreach (var user in WindowsIdentityHelper.GetLoggedOnUsers())
    {
        try
        {
            WriteRegistry(user.Owner.Value);
            Console.WriteLine("Updated user " + user.Name + "  SID " + user.Owner.Value);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetBaseException().Message);
        }
    }
}

 

Notice we’re using WindowsIdentity.Owner.Value to return the SID. The property .Owner.AccountDomainSid doesn’t return the full, correct SID.

Finally, change the Main method.

static void Main(string[] args)
{
    try
    {
        WriteToLoggedOnUsers();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.GetBaseException().Message);
    }
    Console.WriteLine("Finished. Press any key to close.");
    Console.ReadLine();
}

One last thing before running the app. If you really want to test it, create a local user (named Test would be good), log that user on, leave it running and switch back to your regular user.

Now, run the application.

image

Check those User SIDs!

image

image

And finally, to prove the redirection, we’ll look at our CURRENT_USER hive.

image

(Remember, now, to delete those keys. You might also log off and delete the test user.)

Wrap Up

Our goal was to write to the logged on users’ Group Policy keys, with the future intention of preventing them from running certain applications. We need to do this running as System, and found that impersonation wouldn’t work because we had use an elevated process. Instead, we wrote to the running users’ physical registry keys.

One interesting aspect of this session is that there’s not a certain automated way to test for correctness. If I wrote a test that looked at a logical key (like CURRENT_USERS\…), and then checked if the value existed, I wouldn’t know if the correct physical key was updated. This may be a time when a human needs to test. (Maybe there’s a clever way around this, though.)

Full source code can be found after the References.

References

Registry Redirector

Registry Keys Affected by WOW64

Group Policy Object – Disallow Run

WindowsIdentity.Impersonate

Using OpenProcessToken  <=this is where the Win32 code came from. Very useful.

OpenProcessToken function

OpenProcessToken Access Rights

Constants for Token Access Rights

Process.GetProcessesByName

My machine’s named Nesbit, after the great children’s fantasy author.

Full Source

using System;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Diagnostics;
using System.Collections.Generic;

namespace RegistryPrototyping
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                WriteToLoggedOnUsers();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.GetBaseException().Message);
            }
            Console.WriteLine("Finished. Press any key to close.");
            Console.ReadLine();
        }

        static void WriteRegistry(string sid)
        {
            string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer";
            string valueName = "DisallowRun";
            string value = "1";
            keyName = keyName.Replace("HKEY_CURRENT_USER", @"HKEY_USERS\" + sid);
            RegistryValueKind dataType = RegistryValueKind.DWord;
            Registry.SetValue(keyName, valueName, value, dataType);
        }

        static void WriteRegistry()
        {
            string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer";
            string valueName = "DisallowRun";
            string value = "1";
            RegistryValueKind dataType = RegistryValueKind.DWord;
            Registry.SetValue(keyName, valueName, value, dataType);
        }

        static void WriteToLoggedOnUsers()
        {
            foreach (var user in WindowsIdentityHelper.GetLoggedOnUsers())
            {
                try
                {
                    WriteRegistry(user.Owner.Value);
                    Console.WriteLine("Updated user " + user.Name + "  SID " + user.Owner.Value);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.GetBaseException().Message);
                }
            }
        }
    }
}


class WindowsIdentityHelper
{

    [DllImport("advapi32", SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    static extern int OpenProcessToken(
    System.IntPtr ProcessHandle, // handle to process
    int DesiredAccess, // desired access to process
    ref IntPtr TokenHandle // handle to open access token
    );

    [DllImport("kernel32", SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    static extern bool CloseHandle(IntPtr handle);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
    int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

    public const int TOKEN_ASSIGN_PRIMARY = 0x0001;
    public const int TOKEN_DUPLICATE = 0x0002;
    public const int TOKEN_IMPERSONATE = 0x0004;
    public const int TOKEN_QUERY = 0x0008;
    public const int TOKEN_QUERY_SOURCE = 0x0010;
    public const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
    public const int TOKEN_ADJUST_GROUPS = 0x0040;
    public const int TOKEN_ADJUST_DEFAULT = 0x0080;
    public const int TOKEN_ADJUST_SESSIONID = 0x0100;
    public const int TOKEN_READ = 0x00020000 | TOKEN_QUERY;
    public const int TOKEN_WRITE = 0x00020000 | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT;
    public const int TOKEN_EXECUTE = 0x00020000;

    public static List GetLoggedOnUsers()
    {
        List users = new List();
        string errs = "";
        IntPtr hToken = IntPtr.Zero;
        //Get a process that will always be available.
        foreach (Process proc in Process.GetProcessesByName("explorer"))
        {
            try
            {
                if (OpenProcessToken(proc.Handle,
                TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
                ref hToken) != 0)
                {
                    WindowsIdentity newId = new WindowsIdentity(hToken); 
                    CloseHandle(hToken);
                    users.Add(newId);
                }
                else
                {
                    errs += String.Format("OpenProcess Failed {0}, privilege not held\r\n", Marshal.GetLastWin32Error());
                }

            }
            catch (Exception ex)
            {
                errs += String.Format("OpenProcess Failed {0}\r\n", ex.Message);
            }
        }
        if (errs.Length > 0) { throw new Exception(errs); }
        return users;
    }

}