Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usage of Factory / Abstract Factory Design Patterns in Unit Testing

I am told that the Factory / Abstract Factory Design Patterns for writing Unit Test cases is very effective but I havent been able to find any tutorial which clearly demonstrates it. So it will be very helpful if somebody can point me to any existing tutorial or give me some pseudo code and explanation here :)

like image 408
P I Avatar asked Sep 21 '11 23:09

P I


1 Answers

According to GoF, the intent of the Abstract Factory pattern is to provide an interface for creating families of related or dependent objects without specifying their conrcete classes.

In frameworks abstract factories are typically provided using dependency injection, and this is the real key to write code which is easy to test. Dependency injection just means that dependencies are "injected" through the constructor, rather than newed inside the class.

Suppose you use two factories to produce dependencies (here just one dependency, Dice) for easy and hard games of backgammon:

public class EasyGameFactory implements GameFactory
{
  Dice createDice()
  {
    return new LuckyDice();
  }
}

public class NormalGameFactory implements GameFactory
{
  Dice createDice()
  {
    return new RandomDice();
  }
}

For unit testing purposes you would really prefer to use neither of the Dice implementations, so you write a special implementation of GameFactory:

public class CustomGameFactory implements GameFactory
{
  private Dice mDice;

  public CustomGameFactory(Dice dice)
  {
    mDice = dice;
  }

  Dice createDice()
  {
    return mDice;
  }
}

This factory would not have to be part of your production code tree. You supply the factory with a special implementation of Dice through the test code:

public class TestBackgammon
{
  @Test public void shouldReturnDiceThrown() 
  {
    SettableDice dice = new SettableDice();
    Game game = new GameImpl(new CustomGameFactory(dice));

    dice.setDice(new int[] {4, 5});
    game.nextTurn();
    assertArrayEquals(new int[] {4, 5}, game.diceThrown());
  }
}

With this approach any concrete dependency can be injected for testing purposes. However, often the same can be achieved without an Abstract Factory, i.e. rather than injecting a factory, the dependency itself can be injected.

like image 55
Vandhunden Avatar answered Nov 15 '22 09:11

Vandhunden