Click here to Skip to main content
Click here to Skip to main content

Testing Private Methods with Visual Studio

By , 3 Dec 2012
Rate this:
Please Sign up or sign in to vote.

Introduction

When writing unit tests, in most of the cases we have to test private methods. Let's see how this can be achieved using Visual Studio. I will give you three options:

  1. You can test private methods using Reflection, but this is not always a good option, as when you change the name or input arguments of a method, you won't get any error when building, but you will get exceptions run time. We will use the project from my previous post Getting console output within a unit test. We will add a private method to the DummyClass:
    using System;
    
    namespace ConsoleLogger
    {
        public class DummyClass
        {
            public void WriteToConsole(string text)
            {
                Console.Write(text);
            }
    
            private void PrivateWriteToConsole(string text)
            {
                Console.Write("Private: " + text);
            }
        }
    }

    Now we can add a unit test to test the method using reflection:

    [TestMethod]
    public void PrivateWriteToConsoleReflection()
    {
        var currentConsoleOut = Console.Out;
    
        DummyClass target = new DummyClass();
        Type type = typeof(DummyClass);
    
        string text = "Hello";
    
        using (var consoleOutput = new ConsoleOutput())
        {
            var method = type.GetMethod("PrivateWriteToConsole", 
                BindingFlags.NonPublic | BindingFlags.Instance);
            method.Invoke(target, new object[1] { text });
    
            Assert.AreEqual(string.Format("Private: {0}", text), 
                consoleOutput.GetOuput());
        }
    
        Assert.AreEqual(currentConsoleOut, Console.Out);
    }

    We get and invoke the method using reflection.

  2. Another option is to use PrivateObject class. Using it, you can easily call private method, but you have the same problem, you won't get compile exception when name or parameters are changed. Here is the same test written using PrivateObject:
    [TestMethod]
    public void PrivateWriteToConsolePrivateObject()
    {
        var currentConsoleOut = Console.Out;
    
        PrivateObject target = new PrivateObject(typeof(DummyClass));
    
        string text = "Hello";
    
        using (var consoleOutput = new ConsoleOutput())
        {
            target.Invoke("PrivateWriteToConsole", text);
    
            Assert.AreEqual(string.Format("Private: {0}", text), 
                consoleOutput.GetOuput());
        }
    
        Assert.AreEqual(currentConsoleOut, Console.Out);
    }
  3. And here is the third option which I think is the best. You can add .accessor file containing the name of the assembly whose private methods you want to see, or you can use Visual Studio "Create Unit Tests..." wizard to do this for you:

    This will add the following unit test:

    /// <summary>
    ///A test for PrivateWriteToConsole
    ///</summary>
    [TestMethod]
    [DeploymentItem("ConsoleLogger.exe")]
    public void PrivateWriteToConsoleTest()
    {
        DummyClass_Accessor target = 
        new DummyClass_Accessor(); // TODO: Initialize to an appropriate value
        string text = string.Empty; // TODO: Initialize to an appropriate value
        target.PrivateWriteToConsole(text);
        Assert.Inconclusive("A method that does not return a value cannot be verified.");
    }

    We will modify it for our needs:

    /// <summary>
    ///A test for PrivateWriteToConsole
    ///</summary>
    [TestMethod]
    [DeploymentItem("ConsoleLogger.exe")]
    public void PrivateWriteToConsoleTest()
    {
        var currentConsoleOut = Console.Out;
    
        DummyClass_Accessor target = new DummyClass_Accessor();
    
        string text = "Hello";
    
        using (var consoleOutput = new ConsoleOutput())
        {
            target.PrivateWriteToConsole(text);
    
            Assert.AreEqual(string.Format("Private: {0}", text),
                consoleOutput.GetOuput());
        }
    
        Assert.AreEqual(currentConsoleOut, Console.Out);
    }

    When Visual Studio builds the project, it will generate ConsoleLogger_Accessor.exe assembly, containing DummyClass_Accessor class with public methods only.

    Just to mention that you can test internal methods using the same approaches, but you will have one more option - in the AssemblyInfo file of the assembly being tested, you can add  InternalsVisibleTo attribute to specify which assembly will see the internal methods, in our case:

    [assembly: InternalsVisibleTo("ConsoleLogger.Tests")]

    Now we will add an internal method to the same class:

    using System;
    
    namespace ConsoleLogger
    {
        public class DummyClass
        {
            public void WriteToConsole(string text)
            {
                Console.Write(text);
            }
    
            private void PrivateWriteToConsole(string text)
            {
                Console.Write("Private: " + text);
            }
    
            internal void InternalWriteToConsole(string text)
            {
                Console.Write("Internal: " + text);
            }
        }
    }

    and here is the working test method:

    [TestMethod]
    public void InternalWriteToConsoleTest()
    {
        var currentConsoleOut = Console.Out;
    
        DummyClass target = new DummyClass();
    
        string text = "Hello";
    
        using (var consoleOutput = new ConsoleOutput())
        {
            target.InternalWriteToConsole(text);
    
            Assert.AreEqual(string.Format("Internal: {0}", text),
                consoleOutput.GetOuput());
        }
    
        Assert.AreEqual(currentConsoleOut, Console.Out);
    }

The entire code can be found here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Vasil Trifonov
Software Developer (Senior) Telerik
Bulgaria Bulgaria
No Biography provided
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralMissing the point PinmemberJohn Brett2-Dec-12 22:09 
GeneralRe: Missing the point Pinmemberspringy764-Dec-12 0:23 
GeneralRe: Missing the point PinmemberJohn Brett4-Dec-12 0:32 
GeneralRe: Missing the point Pinmemberspringy764-Dec-12 0:56 
GeneralRe: Missing the point PinmemberJohn Brett4-Dec-12 1:11 
GeneralMy vote of 3 PinmemberViolet Tape30-Nov-12 8:53 
GeneralRe: My vote of 3 PinmemberVasil Trifonov2-Dec-12 21:22 
GeneralRe: My vote of 3 PinprotectorPete O'Hanlon3-Dec-12 22:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140415.2 | Last Updated 4 Dec 2012
Article Copyright 2012 by Vasil Trifonov
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid