Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make class more testable?

I have this:

 class FooGenerator:IFooGenerator {
      private object _generated;

      public void Generate() {
         // Generating
         GenerateSmallPart();
         GenerateOtherSmallPart();
         GenerateTinyPart();
         // A lot similar
      }

      private void GenerateSmallPart() {
         //add small part to _generated
      }

      private void GenerateOtherSmallPart() {
         //add small part to _generated
      }

      private void GenerateTinyPart() {
         //add small part to _generated
      }
   }

   internal interface IFooGenerator {
      void Generate();
   }

In my application I use only IFooGenerator via IoC but I want to test all those sub methods.

As I found here, one option is to extract class with all sub methods. But why do i need to do that. It is only being used in FooGenerator.

Do you have any suggestions how can i make my class more testable?

like image 732
Vladimir Nani Avatar asked Apr 10 '13 08:04

Vladimir Nani


People also ask

How do I make my code more testable?

One of the keys to writing highly testable code is to ensure that there is a strong separation between the different parts of an application, with clear, simple APIs for interaction between those parts.

What is a good testable code?

Testable code is code of high quality. It's cohesive and loosely coupled. It's well encapsulated and in charge of its own state. In short, it's singularly defined in its own proper place so that it's straightforward to maintain and extend.


2 Answers

I will share with you how I usually handle this situation. If I see that I want to test some private methods for some reason (like it is hard to stub input parameters to test all code flows) - this usually means for me that complexity of my class is high and I need to refactor my code. In your case (I have no idea what your methods are doing) you can use something like:

interface IPartGenerator
{
   void GeneratePart();
}

class SmallPartGenerator : IPartGenerator
{
   void GeneratePart();
}

class OtherSmallPartGenerator : IPartGenerator
{
   void GeneratePart();
}

class TinyPartGenerator : IPartGenerator
{
   void GeneratePart();
}

class FooGenerator:IFooGenerator 
{
   private IPartGenerator[] partGenerators = new IPartGenerator[] 
                        {
                           new SmallPartGenerator(), 
                           new OtherSmallPartGenerator(), 
                           new TinyPartGenerator ()
                        }

   public void Generate()
   {
        foreach (var partGenerator in partGenerators)
        {
              partGenerator.GeneratePart();
        }
   }
}

Now you can test each of the part generators separately.

like image 95
outcoldman Avatar answered Oct 08 '22 14:10

outcoldman


Who is the client?

Many people (Roy Osherove, Michael Feathers) consider the test client just as valid as the interface or service client.

With that in mind I think it's fine to slightly go against the principle of encapsulation by opening up testable seams by making some private methods public.

like image 44
Neil Thompson Avatar answered Oct 08 '22 13:10

Neil Thompson