views:

404

answers:

9

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 question is, how to use BDD with private methods?
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.

Robert

+4  A: 

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
+8  A: 

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
+10  A: 

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
+1  A: 

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
+7  A: 

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.

eKek0
+1  A: 

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
+4  A: 

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.

Spoike
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
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
A: 

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
A: 

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