Monthly Archives: March 2016

Intelli-Test (Part 2)

I recently posted an article which morphed into a discovery of the Intelli-Test feature in VS2015.

My initial findings were relating to creating a basic intelli-test, and then having that create a new unit test for me. However, once you’ve created an intelli-test, you can modify it; here’s the original intelli-test that was created for me:

        [PexGenericArguments(typeof(int))]
        [PexMethod]
        internal void ClearClassTest<T>(T classToClear)
        {
            Program.ClearClass<T>(classToClear);
            // TODO: add assertions to method ProgramTest.ClearClassTest(!!0)
        }

When this creates a test, it looks like this:


[TestMethod]
[PexGeneratedBy(typeof(ProgramTest))]
public void ClearClassTest861()
{
    this.ClearClassTest<int>(0);
}

So, I tried adding some additional parameters:


    class TestClass
    {
        public string Test1 { get; set; }
        public string Test2 { get; set; }
    }

    /// <summary>This class contains parameterized unit tests for Program</summary>
    [PexClass(typeof(Program))]
    [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))]
    [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)]
    [TestClass]
    public partial class ProgramTest
    {
        /// <summary>Test stub for ClearClass(!!0)</summary>
        [PexGenericArguments(typeof(int))]
        [PexGenericArguments(typeof(string))]
        [PexGenericArguments(typeof(float))]
        [PexGenericArguments(typeof(TestClass))]
        [PexMethod]
        internal void ClearClassTest<T>(T classToClear)
        {
            Program.ClearClass<T>(classToClear);
            // TODO: add assertions to method ProgramTest.ClearClassTest(!!0)
        }
    }

Just re-select “Run intelli-test” and it updates the ProgramTest.ClearClassTest.g.cs, generating 6 new tests. To be honest, this was a bit disappointing. I had expected an “intelligent” test – that is, one that tests several outcomes. To simplify what was happening, I tried creating a simple method:


        public static int TestAdd(int num1, int num2)
        {
            return num1 + num2;
        }

Creating the test for this resulted in this:


        [PexMethod]
        internal int TestAddTest(int num1, int num2)
        {
            int result = Program.TestAdd(num1, num2);
            return result;
            // TODO: add assertions to method ProgramTest.TestAddTest(Int32, Int32)
        }

And then to:


[TestMethod]
[PexGeneratedBy(typeof(ProgramTest))]
public void TestAddTest989()
{
    int i;
    i = this.TestAddTest(0, 0);
    Assert.AreEqual<int>(0, i);
}

So, then I considered what this was actually doing. The purpose of it seems to be to execute code; that is, code coverage; so what happens if I create a method like this:


        public static int TestAdd(int num1, int num2)
        {
            if (num1 > num2)
                return num1 + num2;
            else
                return num2 - num1;
        }

And finally, you see the usefulness of this technology. If it only creates a single test, passing in 0,0 then it only tests one code path. The minimum test to cover all code paths is 0,0 and 1,0. That’s exactly what it does; the generated test looks the same:


        /// <summary>Test stub for TestAdd(Int32, Int32)</summary>
        [PexMethod]
        internal int TestAddTest(int num1, int num2)
        {
            int result = Program.TestAdd(num1, num2);
            return result;
            // TODO: add assertions to method ProgramTest.TestAddTest(Int32, Int32)
        }

But the run intelli-test creates two methods:


[TestMethod]
[PexGeneratedBy(typeof(ProgramTest))]
public void TestAddTest989()
{
    int i;
    i = this.TestAddTest(0, 0);
    Assert.AreEqual<int>(0, i);
}

[TestMethod]
[PexGeneratedBy(typeof(ProgramTest))]
public void TestAddTest365()
{
    int i;
    i = this.TestAddTest(1, 0);
    Assert.AreEqual<int>(1, i);
}

In an effort to confuse the system, I changed the base function:


        public static int TestAdd(int num1, int num2)
        {
            num1++;

            if (num1 == num2)
            {
                throw new Exception("cannot be the same");
            }

            if (num1 > num2)
                return num1 + num2;
            else
                return num2 - num1;
            
        }

And re-run the test; it resulted in 3 tests:

intellitest2

Not sure where the numbers came from, but this tests every code path. The exception results in a fail, but you can mark that as a pass by simply right clicking and selecting “Allow”; which changes the test to look like this:


[TestMethod]
[PexGeneratedBy(typeof(ProgramTest))]
[ExpectedException(typeof(Exception))]
public void TestAddTestThrowsException26601()
{
    int i;
    i = this.TestAddTest(502, 503);
}

Summary

This is basically the opposite of the modern testing philosophy, which is test interactions and behaviour; what this does is establish every code path in a function and run it; so it should establish that the code doesn’t crash, but it obviously can’t establish that it does what it’s intended to do, nor can it establish whether it is sensible to pass, for example, a null value. Having said that, if an object can be null, and there’s no defensive code path to deal with it being passed null, then this will be pointed out.

In general, this is intended for people dealing with, and refactoring, legacy code so that they can adopt the “Stangling Vines” development pattern in order to be sure that the code still does what it did before.

Generic Method to Clear a Class and Intelli-Test

Recently, I published this article on copying a class dynamically. I then found that I could use the same approach to clear a class. Here’s the method:

        private static void ClearClass<T>(T classToClear)
        {
            if (classToClear == null)
                throw new Exception("Must not specify null parameters");

            var properties = classToClear.GetType().GetProperties();

            foreach (var p in properties.Where(prop => prop.CanWrite))
            {
                p.SetValue(classToClear, GetDefault(p.PropertyType));
            }
        }

        /// <summary>
        /// Taken from http://stackoverflow.com/questions/474841/dynamically-getting-default-of-a-parameter-type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object GetDefault(Type type)
        {
            return type.IsValueType ? Activator.CreateInstance(type) : null;
        }

As you can see, I had a little help from Jon Skeet with this one. Once I’d written it, I thought I’d have a play with the IntelliTest feature: if you right click the method and select “Create IntelliTest”, you’re presented with this:

IT1

IT2

It generated this:


    /// <summary>This class contains parameterized unit tests for Program</summary>
    [PexClass(typeof(Program))]
    [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))]
    [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)]
    [TestClass]
    public partial class ProgramTest
    {
        /// <summary>Test stub for ClearClass(!!0)</summary>
        [PexGenericArguments(typeof(int))]
        [PexMethod]
        internal void ClearClassTest<T>(T classToClear)
        {
            Program.ClearClass<T>(classToClear);
            // TODO: add assertions to method ProgramTest.ClearClassTest(!!0)
        }
    }

The interesting thing about this, is that it can’t be found as a test. What actually happens is this creates an intelli-test, which, as far as I can see, you have to right-click on the created test and select “Run Intelli-test”. This then creates you an actual unit test:

IT3

It looks something like this:


namespace ConsoleApplication13.Tests
{
    public partial class ProgramTest
    {

[TestMethod]
[PexGeneratedBy(typeof(ProgramTest))]
public void ClearClassTest861()
{
    this.ClearClassTest<int>(0);
}
    }
}

That then can be found and run:

IT4

Obviously, looking at the unit test, it’s not a particularly good one; it effectively tests that your code doesn’t crash, so it increases your code coverage, but doesn’t really test anything per-se.

Adding and Removing an IIS Application in .NET

Following on from an earlier post about my discovery of an API to control IIS, I had cause to investigate creating a new web application in IIS. The code, again, is remarkably simple:

            ServerManager iisManager = new ServerManager();

            Console.WriteLine("Set-up new site...");

            var sites = iisManager.Sites;

            foreach (var s in sites)
            {
                Console.WriteLine($"Site {s.Name}");

                foreach (var a in s.Applications)
                {
                    Console.WriteLine($"Application {a.Path}");
                }
            }
            Console.WriteLine(" - - - ");

            var defaultSite = sites["Default Web Site"];
            defaultSite.Applications.Add("/Test", @"c:\inetpub\betapps\test");        
            iisManager.CommitChanges();

            Console.ReadLine();

This works fine and, as you can see, is really simple. If you remove the information lines at the top, it’s three lines of code.

Remove it again

To remove the application again, try this:

            var iisManager = new ServerManager();
            var sites = iisManager.Sites;
            var defaultSite = sites["Default Web Site"];
            var testapp = defaultSite.Applications["/Test"];

            if (testapp != null)
            {
                Console.WriteLine("Remove site");
                defaultSite.Applications.Remove(testapp);
                iisManager.CommitChanges();
            }

There is an important note here; simply adding, committing changes and then removing using the same instance of ServerManager will not work. It complains that once CommitChanges is called then the object is read only:

InvalidOperation

The configuration object is read only, because it has been committed by a call to ServerManager.CommitChanges(). If write access is required, use ServerManager to get a new reference.

Also, you can’t just get around this by calling something like:

iisManager = new ServerManager();

Although this does

Dynamically copy a class from one instance to another using reflection

Occasionally, you find that you want to copy a class to another instance of itself. There are various reason, but typically the code can result in a `CopyTo()` function, with a long list of properties to be copied across. There’s nothing wrong with that and, performance-wise, it’s probably faster than what I’m suggesting in this post.

Here’s a generic method that will copy the class for you:

        private static void CopyClass<T>(T copyFrom, T copyTo)
        {
            if (copyFrom == null || copyTo == null)
                throw new Exception("Must not specify null parameters");

            var properties = copyFrom.GetType().GetProperties();

            foreach (var p in properties.Where(prop => prop.CanRead && prop.CanWrite))
            {
                object copyValue = p.GetValue(copyFrom);
                p.SetValue(copyTo, copyValue);
            }
        }

Nothing too onerous if you’ve ever seen reflection, but let’s quickly run through it. The first thing it does is ensure that both to destination and source are provided, then it gets a list of properties that can be read and written to, and copies the value across.

Obviously, this won’t include any private properties.

Here’s some test / example code for it. First, the class to copy:

    class TestClass
    {
        public string teststring { get; set; }

        public string mynextstring { get; set; }

        public void test()
        {

        }

        public int get1 { get { return 1; } }

        //public TestClass2 testClass2 { get; set; }
    }

And then tha calling code:


            TestClass tc = new TestClass()
            {
                //testClass2 = new TestClass2(),
                teststring = "test2123",
                mynextstring = "31"

            };

            var t = new TestClass();
            CopyClass<TestClass>(tc, t);
            Console.WriteLine(t.teststring);
            Console.WriteLine(t.mynextstring);
            //Console.WriteLine(t.testClass2.teststring);

            Console.ReadLine();

Okay, so that works; however, you’ll notice that I’ve included and commented out an external class reference. If you include this, then it will copy the class reference (not the class). What if we want to use this to copy child classes?

Actually, it’s not too complicated:

        private static void CopyClass<T>(T copyFrom, T copyTo, bool copyChildren)
        {
            if (copyFrom == null || copyTo == null)
                throw new Exception("Must not specify null parameters");

            var properties = copyFrom.GetType().GetProperties();

            foreach (var p in properties.Where(prop => prop.CanRead && prop.CanWrite))
            {
                if (p.PropertyType.IsClass && p.PropertyType != typeof(string))
                {
                    if (!copyChildren) continue;

                    var destinationClass = Activator.CreateInstance(p.PropertyType);
                    object copyValue = p.GetValue(copyFrom);

                    CopyClass(copyValue, destinationClass, copyChildren);

                    p.SetValue(copyTo, destinationClass);                  
                }
                else
                {
                    object copyValue = p.GetValue(copyFrom);
                    p.SetValue(copyTo, copyValue);
                }
            }
        }

There’s a couple of things to note here: firstly, we need to check if the value is a class, but exclude strings as a special case (I couldn’t find a neater way of doing this); secondly, create the destination class using reflection and cache the source value. Finally, we just recursively call the function, using generic type inference in order to supply the type (which we don’t have as a generic at this point).

If you now just uncomment out the references to TestClass2 it should recursively copy the class.

I have to be honest and say that I’m not too happy with the check for a string type, but other than that, this is quite a neat little way to copy a class.