views:

447

answers:

10

Let's say I have a project that is a class library. I have a class in that library and this class has some methods that are used inside the class only. Like this:

public class MyClass
{
  public void MyPublicMethod
  {
    int k

    // do something ...

    int z = MyInternalMethod(k);
    // do something else ...

  }

  internal int MyInternalMethod(int i)
  {
        // do something ...

  }
}

Now I want to write unit tests for these methods. I would create a "Unit Tests" project, reference the nunit from it and write something like this

[TestFixture]
public class UnitTests
{
  private MyClass myClass;

  [SetUp]
  public void SetupTest
  {
    myClass = new MyClass();
  }

  [Test]
  public void TestMyInternalMethod
  {
    int z = 100;
    int k = myClass.MyInternalMethod(z); //CAN NOT DO THIS!
    Assert.AreEqual(k, 100000);
  }

  [TearDown]
  public void TearDown
  {
    myClass = null;
  }
}

Of course, I can not do this, because of the MyInternalMethod scope. What would be the proper way to handle this situation?

+3  A: 

You can make internals visible to certain assemblies, check out this post.

Chris Missal
This is the answer that worked best for my situation, and only required adding one line - a gem indeed. Someone downvoted it without stating the reason though ...
Evgeny
I'm curious about the downvote too. Are there drawbacks to testing internals this way versus another?
Chris Missal
A: 

I like to put my unit tests in the same class as the one they are testing. This has two advantages, the first is that it solves the issue you are hitting, the second is that you never lose or forget about them as often ends up being the case if they are in a separate assembly.

Not everyone agrees with that sort of approach (see this SO question I asked previously) but as yet I haven't found or had any flaws in it pointed out to me. I've been doing unit tests that way for going on 4 or 5 years now.

#if UNITTEST
using NUnit.Framework;
#endif

public class MyBlackMagic
{
    private int DoMagic()
    {
        return 1;
    }

    #if UNITTEST

    [TestFixture]
    public class MyBlackMagicUnitTest
    {
         [TestFixtureSetUp]
         public void Init()
         {
             log4net.Config.BasicConfigurator.Configure();
         }

         [Test]
         public void DoMagicTest()
         {
             Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);
             Assert.IsTrue(DoMagic() == 1, "You are not a real magician!");
         }
     }

     #endif
 }
sipwiz
Bad, bad, bad - don't do this please.
Corehpf
But you'll need to reference nunit.framework from any of the projects you have then. I'm not sure if that has any consequences like longer build times, larger executables, but that seems a bit clumsy anyway.
Evgeny
@Corehpf - we're not discussing religion here. If you've got an argument against something provide it.
sipwiz
@Evgeny - referencing nunit has never caused any issues and no noticeable differences in build times. If it's needed the UNITTEST precompiler directive can be easily switched off and the reference can be removed. Or if it's somethings that's needed a lot you can just create different build configurations in VS.Net.
sipwiz
Yuck! At least, put them in a partial class in a different file with a filename like MyBlackMagic.test.cs or something so that they're out of sight and test development occurs in its own file in order not to disturb anything in the actual code.
Mehmet Aras
...and then you use a mocking framework and have to deploy that library too. If you want to use anything like an IoC container you have to make sure that you're not using the test configuration in production. Conditional compilation - shudder. I urge everyone else not to do this!
TrueWill
+4  A: 

Guess it depends on your idea of what a unit is, right? I generally write unit tests for the accessible interface and ignore the private stuff. I've worked with people who will make private things protected (java) for unit test access. I really dislike that approach because it sacrifices the cleanness of the class design for test access.

Agreed. I will use InternalsVisibleTo sometimes, often so I can make certain classes internal but still test them. I won't defend that as good practice, though - in general, test the public interface. It makes refactoring easier (less chance your tests will break).
TrueWill
+2  A: 

Here's a good article on that topic:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

I personally just avoid writing any private methods that do anything really complex. There are other ways to encapsulate behaviors that you don't want to expose, while still giving yourself the ability to test the things that should be hidden. I think there is a tradeoff between perfect encapsulation and testability. Perfect encapsulation is hard to achieve, and it's usually more beneficial to give yourself more insight into the classes. This might be debatable.

Andy White
A: 

Visual Studio can generate private accessors for you. Check out Unit Tests for Private, Internal, and Friend Methods on MSDN. I believe VS2005 simply generated and added private accessor classes to your unit test project. So you had to regenerate them when things changed. However, VS2008 generates a private accessor assembly and makes it available to the unit test project. You're using NUnit but I think it should be ok. Check it out. This way you can keep your actual code free of any testing related code and/or hacks.

Mehmet Aras
A: 

In the past I have created test fixtures in the same namespace and assembly as the class under test to test internal methods. I'm not saying whether internal methods should be tested or not. Pragmatically, you might test them then refactor later.

I have also created partial classes to test private methods and used a compiler directive around the entire part (which was in its own file). Again, not saying this is best, but sometimes you need to move forward.

At build time we could run the unit tests in Debug or Release mode, and we could strip the test code from either build if desired, so there was no harm in putting the test code with the code under test; if anything, it's similar in argument to code-and-data-together = object or object-and-doc-comments = documented-object. In other words: code-and-data-and-test-and-doc-comments-together = cohesive-unit.

An extra time during the build was negligible.

Kit
+2  A: 

i just test the public methods (and no i don't care about coverage metrics, i care about features that work).

note that if the public methods don't use the internal methods then the internal methods do not need to exist!

Steven A. Lowe
+1  A: 

Many people will say that you shouldn't test the internal methods, but instead test them through the public API. Regardless, you can use reflection if you really want to access these private members.

NotDan
A: 

I've used a couple methods for doing this. I've made my private methods protected so that way I can inherit from the class in my unit test and make a “helper” class to test those methods. The other is reflection. The reflection is strait up easier IMO but does go against how your classes should be designed for testing. Here’s a simplified version of what I’m talking about.

public static class ReflectionHelper
{
    public static object RunStaticMethod<TInstance>(string methodName, params object[] methodParams)
    {
        var methodType = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
        return RunMethod<TInstance>(null, methodName, methodType, methodParams);
    }

    public static object RunInstanceMethod<TInstance>(this TInstance instance, string methodName, params object[] methodParams)
    {
        var methodType = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        return RunMethod<TInstance>(instance, methodName, methodType, methodParams);
    }

    private static object RunMethod<TInstance>(object instance, string methodName, BindingFlags methodType, params object[] methodParams)
    {
        var instanceType = typeof(TInstance);
        var method = instanceType.GetMethod(methodName, methodType);
        if (method == null)
        {
            throw new ArgumentException(string.Format("There is no method '{0}' for type '{1}'.", methodName, instanceType));
        }

        var result = method.Invoke(instance, methodParams);

        return result;
    }
}

Given a class such as this

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    internal string GetPrettyName()
    {
        return string.Concat(FirstName, " ", LastName);
    }

    static internal int GetSystemId(string userName)
    {
        // some magic here
        return 13;
    }
}

You'd use these as so

var user = new User { FirstName = "Peter", LastName = "Gibbons" };

var name = user.RunInstanceMethod("GetPrettyName");
Assert.That(name, Is.EqualTo("Peter Gibbons"));

var id = ReflectionHelper.RunStaticMethod<User>("GetSystemId", "tester");
Assert.That(id, Is.EqualTo(13));
Brian Surowiec
+1  A: 

There's two cases: either your private methods get called from some public method, in which case you can test them through that method. Or, they don't get called from some public method, in which they cannot be called at all, are dead code, and should be deleted, not tested.

Note that if you are doing TDD, private methods can only spring into existence by extracting them from public methods, in which case they are already tested automatically.

Jörg W Mittag