17

I am trying to program according to Behavior Driven Development, which states that no line of code should be written without writing failing unit test first.

My questions:

  • how to use BDD with private methods, and
  • how can I unit test private methods?

Is there better solution than:

  • making private methods public first and then making them private when I write public method that uses those private methods;
    or
  • in C# making all private methods internal and using InternalsVisibleTo attribute.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
robert_d
  • 259
  • 1
  • 4
  • 18
  • 3
    See http://stackoverflow.com/questions/34571/whats-the-best-way-of-unit-testing-private-methods and http://stackoverflow.com/questions/105007/do-you-test-private-method for some insightful answers – David Johnstone Apr 12 '10 at 04:42
  • please ignore the top-voted answer in question#1 or rather skip ahead to the second one posted by David. Do your team a favor; use reflection only as a last resort (and other clever ways to get at stuff that the designer of the class did NOT want to expose). Prefer simple. – Gishu Dec 29 '11 at 06:45
  • Possible duplicate of [How do I test a class that has private methods, fields or inner classes?](https://stackoverflow.com/questions/34571/how-do-i-test-a-class-that-has-private-methods-fields-or-inner-classes) – Raedwald Dec 14 '17 at 13:13

12 Answers12

22

When you write code test-first, you write against the public interface. There are no private methods at this point.

Then you write the code to pass the test. If any of that code gets factored into a private method, that's not important -- it should still be there only because it is used by the public interface.

If the code isn't written test first, then -- in .net, anyway -- reflection can be used to directly prod private methods; though this is a technique of last resort.

Steve Gilham
  • 11,237
  • 3
  • 31
  • 37
10

Private methods are internal implementation details. They should not be tested directly, as they will be tested indirectly via testing your public interface. If for some reason a private method is not covered when your public interface is fully tested, then the private method is not required, and it should be removed.

Generally, it is a bad idea to bind test code to private implementation details. That couples your test to those private details, reducing your freedom to change those details at will, even if they don't affect the publicly facing interface and behavior. That increases the amount of effort required to write and maintain your unit tests, which is a negative thing. You should strive for as much coverage as possible, while only binding to the public interface.

jrista
  • 32,447
  • 15
  • 90
  • 130
8

Short answer: You don't test private methods.

If you have programmed well, the code coverage of your tests should be testing private methods implicitly.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
eKek0
  • 23,005
  • 25
  • 91
  • 119
6

If a private method method exists, it's there to be used by a public method. Therefore I'd write a test for the public method.

I write my tests to test the public parts of a class. If the class is well designed then the private parts get tested by default.

If the private method isn't called from a public method, then why does it exist?

In your case I'd do the following

* Write failing test for the public method
* Write public method that calls the private method that doesn't exist yet(test still fails as your class is incomplete
* Write the private method
* Test should now pass
Glen
  • 21,816
  • 3
  • 61
  • 76
6

Short answer: You can't test a private method.

Long answer: You can't test a private method, but if you're inclined to test whatever it does consider refactoring your code. There are two trivial approaches:

  • Test the public method that accesses the private method.
  • Extract the private code to its own class, i.e. move the implementation so it can become appropriately public.

The first one is simple but has a tendency to let you shoot your own foot as you write more tests and the latter promotes better code and test design.

Contrived answer: Okay, so I lied. You can test a private method with the help of some reflection magic (some TDD tools support testing private methods). In my experience though, it leads to convoluted unit tests. Convoluted unit tests leads to worse code. Worse code leads to anger. Anger leads to hate. Hate leads to suffering

The direct effect of production code becoming worse is that the class under test tend to become large and handles many things (violation of Single Responsibility Principle) and harder to maintain. This defeats the purpose of TDD, that is to get production code testable, extensible and more importantly: reusable.

If you're writing tests for a class that is deployed, you could investigate everything that calls the private method and write tests accordingly. If you have the chance to rewrite the class then please do refactor it by splitting the class up. If you're lucky then you'll end up with some code reuse that you can utilize.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
Spoike
  • 119,724
  • 44
  • 140
  • 158
  • the long answer might be slightly amended to indicate that you can test private methods in .NET with TypeMock Isolator - http://learn.typemock.com/isolator-features/test-the-un-testable/change-behavior-of-internalprivate-or-protected-methods-easi.html – Russ Cam Oct 17 '09 at 23:38
  • Amended the answer but I have a radical view about how to deal with private methods... While I TDD I only end up with private methods because of a refactoring step and not initially because of a test I wrote. I.e. a private method is code that was extracted from a public method. If I see that piece of functionality becoming something "more" it often makes sense to move that code to another class. – Spoike Oct 18 '09 at 00:49
3

We can Unit Test static and instance private methods using PrivateType and PrivateObject respectively. The following 2 articles explains these techniques

1. Unit Test Private Static Method in C#.NET

2. Unit Test Private Instance Method in C#.NET

Suresh
  • 31
  • 1
2

I agree with the point that has been made about not testing private methods per se and that tests should be written against the public API, but there is another option you haven't listed above.

You could make the methods protected then derive from the class under test. You can expose the base protected method with a public method on the derived class, for example,

public class TestableClassToTest : ClassToTest
{
    public new void MethodToTest() 
    { 
        base.MethodToTest(); 
    } 
}

You might be using this Extract and Override pattern already to override virtual properties of the base class for dependency injection, in which case this may be a viable option for you.

Russ Cam
  • 124,184
  • 33
  • 204
  • 266
2

Mbunit Reflector helps you with this.

Reflector objectReflection = new Reflector(new ObjectWithprivateMethods());
objectReflection.InvokeMethod(AccessModifier.NonPublic,,"Add",1,6));

A blog post about it.

Carl Bergquist
  • 3,894
  • 2
  • 25
  • 42
2

I've been fighting with it for over 1 month, but found the answer:

        var objectOfPrivateMethod = new ObjectOfPrivateMethod(); //yes here is contructor
        object[] arguments = {  }; // here as Object you provide arguments

        var extractedPrivateMethod = typeof(ObjectOfPrivateMethod).GetMethod("Name_Of_Private_Method", BindingFlags.NonPublic|BindingFlags.Static); //if fails returns null. delete flag static if it's not static. Returns your method as an object.
        Assert.AreNotEqual(null, extractedPrivateMethod, "Mathod does not exist"); // good to catch if even exists.

        object result = extractedPrivateMethod.Invoke(null, arguments); // here as object you'll get return value of your function. change null for object of class where is method, if your method is not static 

that's all.

1

You should only be testing the external API of your classes, i.e. the public methods. If your tests aren't hitting code in the private methods then either you need to write more tests or refactor the class.

The whole point of testing an API, especially one that will be distributed to third parties, is that you can change the internal structure of the class as much as you want, as long as you don't break the external contract of it's public methods.

As you've identified, this is where BDD comes into play over 'traditional' TDD using mock classes, where every method call has to be set-up in advance for the test. I'm not an expert on either of these, hopefully someone else can answer that one better than I can.

roryf
  • 29,592
  • 16
  • 81
  • 103
0

If you really believe that a private method is complex enough that it deserves unit tests of it's own - it's an indicator that your class is doing too much and you should extract part or all of that private method into a class of its own behind an interface.

Mock the interface when testing the original class. You should now have a public accessor to the new class which was previously the private method.

Sometimes when dealing with old code that was either poorly written or not written using TDD there may be a need to test the private classes. In this case you should use reflection, but where possible update the code to follow closer to the TDD approach.

SamuelDavis
  • 3,312
  • 3
  • 17
  • 19
0

If you find yourself wanting to test a private method then there is something complex in it and you are probably right to want to test it, this is a design smell. Exposing the method on the interface just swaps one smell for another worse one.

Time to refactor :)

Usually I factor out the inner complexity into a helper class. However check the method for 'Feature Envy' or 'Inappropriate Intimacy'. There may be a better place for the method to live. With Extension methods in .net now, even base types could be a good candidate.

Good Luck

Nigel Thorne
  • 21,158
  • 3
  • 35
  • 51