views:

80

answers:

5

Hi,

I've got a class with one public method and many private methods which are run depending on what parameter are passed to the public method so my code looks something like:

public class SomeComplexClass
{
    IRepository _repository;

    public SomeComplexClass()
       this(new Repository())
    {
    }

    public SomeComplexClass(IRepository repository)
    {
        _repository = repository;
    }


    public List<int> SomeComplexCalcualation(int option)
    {
        var list = new List<int>();

        if (option == 1)
            list = CalculateOptionOne();
        else if (option == 2)
            list = CalculateOptionTwo();
        else if (option == 3)
            list = CalculateOptionThree();
        else if (option == 4)
            list = CalculateOptionFour();
        else if (option == 5)
            list = CalculateOptionFive();

        return list;
    }

    private List<int> CalculateOptionOne()
    {
        // Some calculation
    }

    private List<int> CalculateOptionTwo()
    {
        // Some calculation
    }

    private List<int> CalculateOptionThree()
    {
        // Some calculation
    }

    private List<int> CalculateOptionFour()
    {
        // Some calculation
    }

    private List<int> CalculateOptionFive()
    {
        // Some calculation
    }
}

I've thought of a few ways to test this class but all of them seem overly complex or expose the methods more than I would like. The options so far are:

  • Set all the private methods to internal and use [assembly: InternalsVisibleTo()]

  • Separate out all the private methods into a separate class and create an interface.

  • Make all the methods virtual and in my tests create a new class that inherits from this class and override the methods.

Are there any other options for testing the above class that would be better that what I've listed?

If you would pick one of the ones I've listed can you explain why?

Thanks

+3  A: 

How about OptionCalculators, to which the original class dispatches the work? Each would have just one method, CalculateOption, and of course it would be public, and therefore readily testable.

Carl Manaster
+6  A: 

You don't need to change your interface to test these methods. Simply test the public interface thoroughly to ensure that all the private methods are tested:

 void Test1() 
 {
      new SomeComplexClass(foo).SomeComplexCalcualation(1);
 } 

 void Test2() 
 {
      new SomeComplexClass(foo).SomeComplexCalcualation(2);
 } 

and so on...

You can use a coverage tool (e.g. NCover for .NET) to ensure that all the code you wanted to test has actually been tested.

Mark Byers
A: 

You should only need to test the public methods of the Class/Interface.

You just need to be sure you have enough Unit test cases to thoroughly test all the different behaviors of those public methods (which would excersise the private methods appropriately).

Justin Niessner
A: 

If each of those computations is that complex, is each one really a single method? If those computations share code, or should be multiple methods each, it's an argument for the interface/Strategy approach you mention, so you can test each of those steps.

Another thing to consider: thoroughly exercising the one public method is testing two things a) that the ComputeOptionN code is working, AND b) that the option checking is working properly.

Not a problem if you're literally passing in ints, but not ideal, especially if the comparison could ever get more complicated, or if it might change around.

LH
A: 

@Carl is right. This is nothing more than utilizing a strategy pattern. Store all the calculators in an array inject the array into SomeComplexClass. This will allow you to unit test each calculator by itself and the SomeComplexClass. Now you can do this:

public List<int> SomeComplexCalcualation(int option)
{
     return calculator.find(option);
}

Very easy to mock calculator

Gutzofter