Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Monday, August 10, 2009

Static Typing gives you a head start, Tests help you finish

In one of my earlier posts (almost a year back) I had indicated how type driven modeling leads to succinct domain structures that inherit the following goodness :

  • Lesser amount of code to write, since the static types encapsulate lots of business constraints

  • Lesser amount of tests to write, since the compiler writes them implicitly for you


In a recent thread on Twitter, I had mentioned about a comment that Manuel Chakravarty made in one of the blog posts of Micheal Feathers ..

"Of course, strong type checking cannot replace a rigorous testing discipline, but it makes you more confident to take bigger steps."

The statement resonated my own feelings on static typing that I have been practising for quite some time now using Scala. Since the twitter thread became louder, Patrick Logan made an interesting comment in my blog on this very subject ..

This is interesting... it is a long way toward the kind of explanation I have been looking for re: "type-driven programming" with rich type systems as opposed to "test-driven programming" with dynamic languages.

I am still a big fan of the latter and do not fully comprehend the former.

I'd be interested in your "type development" process - without "tests" of some kind, the type system may validate the "type soundness" of your types, but how do you know they are the types you actually *want* to have proven sound?


and the conversation became somewhat longer where both of us were trying to look into the practices and subtleties that domain modeling with type constraints imply on the programmer. One of the points that Patrick raised was regarding the kind of tests that you would typically provide for a code like this.

Let me try to look into some of the real life coding that I have been using this practice on. When I have a code snippet like this ..

/**
 * A trade needs to have a Trading Account
 */
trait Trade {
  type T
  val account: T
  def valueOf: Unit
}

/**
 * An equity trade needs to have a Stock as the instrument
 */
trait EquityTrade extends Trade {
  override def valueOf {
    //.. calculate value
  }
}

/**
 * A fixed income trade needs to have a FixedIncome type of instrument
 */
trait FixedIncomeTrade extends Trade {
  override def valueOf {
    //.. calculate value
  }
}
//..
//..

/**
 * Accrued Interest is computed only for fixed income trades
 */
trait AccruedInterestCalculatorComponent {
  type T

  val acc: AccruedInterestCalculator
  trait AccruedInterestCalculator {
    def calculate(trade: T)
  }
}


I need to do validations and write up unit and functional tests to check ..

  • EquityTrade needs to work only on equity class of instruments

  • FixedIncomeTrade needs to work on fixed incomes only and not on any other instruments

  • For every method in the domain model that takes an instrument or trade, I need to check if the passed in instrument or trade is of the proper type and as well write unit tests that check the same. AccruedInterestCalculator takes a trade as an argument, which needs to be of type FixedIncomeTrade, since accrued interest is only meaningful for bond trades only. The method AccruedInterestCalculator#calculate() needs to do an explicit check for the trade type which makes me write unit tests as well for valid as well as invalid use cases.


Now let us introduce the type constraints that a statically typed language with a powerful type system offers.

trait Trade {
  type T <: Trading
  val account: T

  //..as above
}

trait EquityTrade extends Trade {
  type S <: Stock
  val equity: S

  //.. as above
}

trait FixedIncomeTrade extends Trade {
  type FI <: FixedIncome
  val fi: FI

  //.. as above
}
//..


The moment we add these type constraints our domain model becomes more expressive and implicitly constrained with a lot of business rules .. as for example ..

  1. A Trade takes place on a Trading account only

  2. An EquityTrade only deals with Stocks, while a FixedIncomeTrade deals exclusively with FixedIncome type of instruments


Consider this more expressive example that slaps the domain constraints right in front of you without them being buried within procedural code logic in the form of runtime checks. Note that in the following example, all the types and vals that were left abstract earlier are being instantiated while defining the concrete component. And you can only instantiate honoring the domain rules that you have defined earlier. How useful is that as a succinct way to write concise domain logic without having to write any unit test ?

object FixedIncomeTradeComponentRegistry extends TradingServiceComponentImpl
  with AccruedInterestCalculatorComponentImpl
  with TaxRuleComponentImpl {

  type T = FixedIncomeTrade
  val tax = new TaxRuleServiceImpl
  val trd = new TradingServiceImpl
  val acc = new AccruedInterestCalculatorImpl
}


Every wiring that you do above is statically checked for consistency - hence the FixedIncome component that you build will honor all the domain rules that you have stitched into it through explicit type constraints.

The good part is that these business rules will be enforced by the compiler itself, without me having to write any additional explicit check in the code base. And the compiler is also the testing tool - you will not be able to instantiate a FixedIncomeTrade with an instrument that is not a subtype of FixedIncome.

Then how do we test such type constrained domain abstractions ?

Rule #1: Type constraints are tested by the compiler. You cannot instantiate an inconsistent component that violates the constraints that you have incorporated in your domain abstractions.

Rule #2: You need to write tests for the business logic only that form the procedural part of your abstractions. Obviously! Types cannot be of much help there. But if you are using a statically typed language, get the maximum out of the abstractions that the type system offers. There are situations when you will discover repetitive procedural business logic with minor variations sprinkled across the code base. If you are working with a statically typed language, model them up into a type family. Your tests for that logic will be localized *only* within the type itself. This is true for dynamically typed languages as well. Where static typing gets the advantage is that all usages will be statically checked by the compiler. In a statically typed language, you think and model in "types". In a dynamically typed languages you think in terms of the messages that the abstrcation needs to handle.

Rule #3: But you need to create instances of your abstractions within the tests. How do you do that ? Very soon you will notice that the bulk of your tests are being polluted by complicated instantiations using concrete val or type injection. What I do usually is to use the generators that ScalaCheck offers. ScalaCheck offers a special generator, org.scalacheck.Arbitrary.arbitrary, which generates arbitrary values of any supported type. And once you have the generators in place, you can use them to write properties that do the necessary testing of the rest of your domain logic.

Tuesday, May 29, 2007

Parameterizing Test Methods - Revisited

In my last post on refactoring and unit tests, Steve Freeman noted in one of his blog comments ..

I can't see the point in the data provider. Why don't you just call the method three times with different arguments?


In the process of refactoring, I had used TestNG's parameterized test method feature to decouple test data from test methods. While invoking a test method multiple times with different parameter gives me the same functional result, parameterized test methods provide great scalability and a neat separation between the test logic and test data suite. Complex business methods may involve lots of complicated calculations and conditionals - a unit test of the method needs to ensure all conditionals are exercised to ensure full coverage. This may result in lots of data combinations, which if handled directly through separate invocations of the same test methods may result in real explosion of test cases.

The feature of parameterizing test methods in TestNG through DataProviders provide a great way to DRY up the test methods. I can have the test data combination either in testNG.xml or in separate factory methods with specific signatures that provide huge extensibility. The test method can then have parameters and an annotation that specify the data source. Take the following example from the earlier post :


public class AccruedInterestCalculatorTest extends MockControl {
  //..
  @DataProvider(name = "test1")
  public Object[][] createAccruedInterestCalculationData() {
    return new Object[][] {
      {20, BigDecimal.valueOf(0.5), BigDecimal.valueOf(1000), BigDecimal.valueOf(30)},
      {20, BigDecimal.valueOf(0.5), BigDecimal.valueOf(2000), BigDecimal.valueOf(60)},
      {30, BigDecimal.valueOf(0.5), BigDecimal.valueOf(2000), BigDecimal.valueOf(90)},
    };
  }

  //..

  // the test method now accepts parameters
  //..
  @Test(dataProvider = "test1")
  public void normalAccruedInterest(int days,
    BigDecimal rate, BigDecimal principal, BigDecimal interestGold) {
    new CalculatorScaffold()
      .on(principal)
      .forDays(days)
      .at(rate)
      .calculate()
      .andCheck(interestGold);
  }
  //..
}



The calculation of the accrued interest is an extremely complicated business method which needs to consider lots of alternate routes of computation and contextual data. A typical data set for testing the calculation effectively will result in repeating the test method invocation lots of times. Instead of that, the parameterization technique allows me to declare all the varying components as parameters of the test method. And the data source comes from the method createAccruedInterestCalculationData(), suitably annotated with a data source name.

Making the test method parameterized has the additional side-effect of decoupling the data set from the logic - the entire data set can be populated by non-programmers as well, typically domain guys who can enrich the test coverage by simply putting in additional data points in the factory method that generates the data. We have actually used this technique in a real life project where domain experts took part in enriching parameterized unit test cases through data fulfillment in data provider methods.

There's actually more to it. The data provider method can be used to fetch data from other complicated data sources as well e.g. database, XML etc. and with logic to generate data also. All these can be encapsulated in the DataProvider methods and transparently fed to the test methods. The logic of test data generation is completely encapsulated outside the test method. I found this feature of TestNG a real cracker ..

Sunday, May 20, 2007

Refactoring Unit Test Methods to speak the Domain

I do TDD, but I do not start writing unit tests before writing production code. It's not that I didn't try - I gave it an honest attempt for quite some time, before I gave up. Somehow the approach of writing tests first does not seem intuitive to me. At least I need to figure out the collaborators and the initial subset of public contracts before my TestNG plugin kicks in. Since then, it's all a game of collaborative pingpong between my production code and test code. Having said that, I honestly believe that an exhaustive unit test suite is no less important than the code itself. I take every pain to ensure that my unit tests are well organized, properly refactored and follow all principles of good programming that I espouse while writing the actual production code.

Refactoring is one practice that I preach, teach and encourage vigorously to my teammates. Same for unit tests - if I strive to make my production code speak the language of the domain, so should be my unit tests. This post is about a similar refactoring exercise to make unit tests speak the DSL. At the end of this effort of vigorous iterations and cycles of refactoring, we could achieve a well engineered unit test suite, which can probably be enhanced by the domain guys with minimum of programming knowledge.

The Class Under Test

The following is the fragment of a simplified version of an AccruedInterestCalculator, a domain class, which calculates the interest accrued for a client over a period of time. For brevity, I have a very simplified version of the class with only very simple domain logic. The idea is to develop a fluent unit test suite for this class that speaks the domain language through an iterative process of refactoring. I will be using the artillery consisting of the state of the art unit testing framework (TestNG), a dynamic mocking framework (EasyMock) and the most powerful weapon in programming - merciless refactoring.


public class AccruedInterestCalculator {
  //..
  //..
  private IAccruedDaysCalculator accruedDaysCalculator;
  private IInterestRateCalculator interestRateCalculator;

  public final BigDecimal calculateAccruedInterest(final BigDecimal principal)
    throws NoInterestAccruedException {
    int days = accruedDaysCalculator.calculateAccruedDays();
    if (days == 0) {
      throw new NoInterestAccruedException("Zero accrual days for principal " + principal);
    }
    BigDecimal rate = interestRateCalculator.calculateRate();
    BigDecimal years = BigDecimal.valueOf(days).divide(BigDecimal.valueOf(365), 2, RoundingMode.UP);
    return principal.multiply(years).multiply(rate);
  }

  AccruedInterestCalculator setAccruedDaysCalculator(IAccruedDaysCalculator accruedDaysCalculator) {
    this.accruedDaysCalculator = accruedDaysCalculator;
    return this;
  }

  AccruedInterestCalculator setInterestRateCalculator(IInterestRateCalculator interestRateCalculator) {
    this.interestRateCalculator = interestRateCalculator;
    return this;
  }
}



and the two collaborators ..


public interface IAccruedDaysCalculator {
  int calculateAccruedDays();
}

public interface IInterestRateCalculator {
  BigDecimal calculateRate();
}



Mocks are useful, but Noisy ..

I am a big fan of using mocks for unit testing - EasyMock is my choice of dynamic mocking framework. Mocks provide the most seamless way of handling collaborators while writing unit tests for a class. However, often, I find mocks introducing lots of boilerplate codes which need to be repeated for every test method that I write ..


public class AccruedInterestCalculatorTest {
  protected IMocksControl mockControl;

  @BeforeMethod
  public final void setup() {
    mockControl = EasyMock.createControl();
  }

  @Test
  public void normalAccruedInterestCalculation() {
    IAccruedDaysCalculator acalc = mockControl.createMock(IAccruedDaysCalculator.class);
    IInterestRateCalculator icalc = mockControl.createMock(IInterestRateCalculator.class);

    expect(acalc.calculateAccruedDays()).andReturn(2000);
    expect(icalc.calculateRate()).andReturn(BigDecimal.valueOf(0.5));

    mockControl.replay();

    BigDecimal interest =
      new AccruedInterestCalculator()
        .setAccruedDaysCalculator(acalc)
        .setInterestRateCalculator(icalc)
        .calculateAccruedInterest(BigDecimal.valueOf(2000.00));

    mockControl.verify();
  }
}



Refactoring! Refactoring!

Have a look at the above test method - the mock framework setup and controls pollute the actual business logic that I would like to test. Surely, not a very domain friendly approach. As Howard has pointed to, in one of his NFJS writings, we can abstract away the mock stuff into separate methods within the test class, or still better in a separate MockControl class altogether. This makes the actual test class lighter and free of some of the noise. Here is the snapshot after one round of refactoring ..


// mock controls delegated to class MockControl
public class AccruedInterestCalculatorTest extends MockControl {

  @BeforeMethod
  public final void setup() {
    mockControl = EasyMock.createControl();
  }

  @Test
  public void normalAccruedInterestCalculation() {
    IAccruedDaysCalculator acalc = newMock(IAccruedDaysCalculator.class);
    IInterestRateCalculator icalc = newMock(IInterestRateCalculator.class);

    expect(acalc.calculateAccruedDays()).andReturn(2000);
    expect(icalc.calculateRate()).andReturn(BigDecimal.valueOf(0.5));

    replay();

    BigDecimal interest =
      new AccruedInterestCalculator()
        .setAccruedDaysCalculator(acalc)
        .setInterestRateCalculator(icalc)
        .calculateAccruedInterest(BigDecimal.valueOf(2000.00));

    verify();
  }
}



and the new MockControl class ..


public abstract class MockControl {
  protected IMocksControl mockControl;

  protected final <T> T newMock(Class<T> mockClass) {
    return mockControl.createMock(mockClass);
  }

  protected final void replay() {
    mockControl.replay();
  }

  protected final void verify() {
    mockControl.verify();
  }
}



The test class AccruedInterestCalculatorTest is now cleaner and the test method is lighter in baggage from the guts of the mock calls. But still it is not sufficiently close to speaking the domain language. One of the litmus tests which we often do to check the domain friendliness of unit tests is to ask a domain guy to explain the unit test methods (annotated with @Test) and, if possible, to enhance them. This will definitely be a smell to them, with the remaining litterings of mock creation and training still around. The domain guy in this case, nods a big NO, Eclipse kicks in, and we start the next level of refactoring.

One thing strikes me - each test method is a composition of the following steps :

  1. create mocks

  2. setup mocks

  3. replay

  4. do the actual stuff

  5. verify


And refactoring provides me the ideal way to scaffold all of these behind fluent interfaces for the contract that we plan to test. How about a scaffolding class that encapsulates these steps ? I keep the scaffold as a private inner class and try to localize all the mockeries in one place. And the scaffold can always expose fluent interfaces to be used by the test methods. Here is what we have after a couple of more rounds of iterative refactoring ..


public class AccruedInterestCalculatorTest extends MockControl {
  private IAccruedDaysCalculator acalc;
  private IInterestRateCalculator icalc;

  @BeforeMethod
  public final void setup() {
    mockControl = EasyMock.createControl();
    acalc = newMock(IAccruedDaysCalculator.class);
    icalc = newMock(IInterestRateCalculator.class);
  }

  // the scaffold class encapsulating all mock methods
  private class CalculatorScaffold {
    private BigDecimal principal;
    private int days;
    private BigDecimal rate;
    private BigDecimal interest;

    CalculatorScaffold on(BigDecimal principal) {
      this.principal = principal;
      return this;
    }

    CalculatorScaffold forDays(int days) {
      this.days = days;
      return this;
    }

    CalculatorScaffold at(BigDecimal rate) {
      this.rate = rate;
      return this;
    }

    CalculatorScaffold calculate() {
      expect(acalc.calculateAccruedDays()).andReturn(days);
      expect(icalc.calculateRate()).andReturn(rate);

      replay();

      interest =
        new AccruedInterestCalculator()
        .setAccruedDaysCalculator(acalc)
        .setInterestRateCalculator(icalc)
        .calculateAccruedInterest(principal);

      verify();
      return this;
    }

    void andCheck(BigDecimal interestGold) {
      assert interest.compareTo(interestGold) == 0;
    }
  }

  //..
  //.. the actual test methods

  @Test
  public void normalAccruedInterest() {
    new CalculatorScaffold()
      .on(BigDecimal.valueOf(1000.00))
      .forDays(days)
      .at(BigDecimal.valueOf(0.5))
      .calculate()
      .andCheck(BigDecimal.valueOf(30.0));
  }

  @Test
  public void normalAccruedInterest() {
      new CalculatorScaffold()
      .on(BigDecimal.valueOf(2000.00))
      .forDays(days)
      .at(BigDecimal.valueOf(0.5))
      .calculate()
      .andCheck(BigDecimal.valueOf(60.0));
  }

  //..
  //.. other methods
}



This class has test methods which now look more closer to the domain, with all mock controls refactored away to the scaffold class. Do you think the domain guys will be able to add more methods to add to the richness of coverage ? The accrued interest calculation is actually quite complicated with more collaborators and more domain logic than what I have painted here. Hence it is quite natural that we need to enrich the test cases with more possibilities and test coverage. Instead of making separate methods which work on various combinations of days, rate and principal (and other factors in reality), why not DRY them up with parameterized tests ?

Parameterized Tests in TestNG

TestNG provides a great feature for providing parameters in test methods using the DataProvider annotation. DRY up your test methods with parameters .. here is what it looks like in our case ..


public class AccruedInterestCalculatorTest extends MockControl {
  private IAccruedDaysCalculator acalc;
  private IInterestRateCalculator icalc;

  @BeforeMethod
  public final void setup() {
    mockControl = EasyMock.createControl();
    acalc = newMock(IAccruedDaysCalculator.class);
    icalc = newMock(IInterestRateCalculator.class);
  }

  @DataProvider(name = "test1")
  public Object[][] createAccruedInterestCalculationData() {
    return new Object[][] {
      {20, BigDecimal.valueOf(0.5), BigDecimal.valueOf(1000), BigDecimal.valueOf(30)},
      {20, BigDecimal.valueOf(0.5), BigDecimal.valueOf(2000), BigDecimal.valueOf(60)},
      {30, BigDecimal.valueOf(0.5), BigDecimal.valueOf(2000), BigDecimal.valueOf(90)},
    };
  }

  private class CalculatorScaffold {
    //..
    //.. same as above
  }

  // the test method now accepts parameters
  //..
  @Test(dataProvider = "test1")
  public void normalAccruedInterest(int days,
    BigDecimal rate, BigDecimal principal, BigDecimal interestGold) {
    new CalculatorScaffold()
      .on(principal)
      .forDays(days)
      .at(rate)
      .calculate()
      .andCheck(interestGold);
  }

  @Test(expectedExceptions = {NoInterestAccruedException.class})
  public void zeroAccruedDays() {
    new CalculatorScaffold()
      .on(BigDecimal.valueOf(2000))
      .forDays(0)
      .at(BigDecimal.valueOf(0.5))
      .calculate()
      .andCheck(BigDecimal.valueOf(90));
  }
}



The test methods look DRY, speak the domain language and do no longer have to administer the mock controls. All test conditions and results are now completely decoupled from the test methods and fed to them through the annotated provider methods. Now the domain guy is happy!

Wednesday, May 02, 2007

Unit Tests - Another Great Tool for Refactoring

In my last post on unit testing, I had talked about some techniques on how to make your classes unit test friendly. Unit testing is the bedrock of writing good software - never compromise on writing unit tests for the next class that you design. Unit testing is about testing classes in isolation - get them out of the natural environment and take them for a ride. That way unit tests give you a feedback about the correctness of the behavior of the *unit* as a whole. The other aspect of unit tests which I find extremely useful while designing classes is the support for refactoring. Unit tests are great vehicles for refactoring object collaborations - thus there is a 2-way feedback loop between class design and its unit test design. And once you have cycled through rounds of iteration in this feedback loop, you can expect to have stabilized your abstractions and collaborations.

Here's an example ..


class Payroll {
  // ..
  // ..

  void calculateSalary(Employee emp) {
    BigDecimal charge = emp.getSalary();
    // calculate total salary including taxes
  }
}



When I look at the possible unit test for the class Payroll, the first thing that strikes me is the argument Employee in calculateSalary(). The first attempt tries to instantiate an Employee and invoke the method calculateSalary() from the test case :


class PayrollTest extends TestCase {
  // ..
  // ..

  public void testSalaryCalculation() {
    Employee emp = new Employee(..);
    // ..
  }
}



A Mockery of sorts ..

Instantiating an Employee object brings into action lots of other machineries like the database layer, the ORM layer etc., which we already know should be best kept away from the unit test harness. Think Mocks ..

When you need to mock a concrete class, take a second look, if necessary take a third look as well. Mock roles, not objects and roles are best specified through interfaces. In the above example, we are really exploiting the fact that an employee is salaried and has a basic salary component for being employed in a company. In this method calculateSalary(), we are not concerned with the other details of the Employee class, which may be used in other context within the software.

Extract Interface

Now I have a new interface Salaried as :


interface Salaried {
  BigDecimal getBasicSalary();
}



and ..


public class Employee implements Salaried {
  // ..
}



The method calculateSalary() now takes an interface Salaried instead of the concrete class Employee - and the mock becomes idiomatic in the test case (I am using EasyMock as the mocking framework) :


class Payroll {
  // ..
  // ..

  public void calculateSalary(Salaried emp) {
    // ..
  }
}

class PayrollTest extends TestCase {
  // ..
  // ..

  public void testSalaryCalculation() {
    IBillable mock = createMock(Salaried .class);
    expect(mock.getBasicSalary()).andReturn(BigDecimal.valueOf(7000));
    replay(mock);
    // ..
  }
}




Thus unit testing helped me use the Extract Interface principle and improve the collaboration between my classes. Notice how the class Payroll now collaborates with a more generic role Salaried instead of a concrete class Employee. Tomorrow if the company decides to employ contractors with different salary computation, we will have a separate abstraction :


public class Contractor implements Salaried {
  // ..
  // ..
  BigDecimal getBasicSalary() {
    // .. different implementation than Employee
  }
  // ..
}



but the class Payroll remains unaffected, since it now collaborates with Salaried and NOT any concrete implementation.

Friday, March 30, 2007

Making Classes Unit-Testable

I had been working on the code review of one of our Java projects, when the following snippet struck me as a definite smell in one of the POJOs :


class TradeValueCalculator {
  // ..
  // ..

  public BigDecimal calculateTradeValue(final Trade trade, ..) {
    // ..
    BigDecimal tax = TradeUtils.calculateTax(trade);
    BigDecimal commission = TradeUtils.calculateCommission(trade);
    // .. other business logic to compute net value
  }
  // ..
  // ..
}



What is the problem with the above two innocuous looking Java lines of code ? The answer is very simple - Unit Testability of the POJO class TradeValueCalculator ! Yes, this post is about unit testability and some tips that we can follow to design classes that can be easily unit tested. I encountered many of these problems while doing code review of a live Java project in recent times.

Avoid Statics

When it comes to testability, statics are definitely not your friends. In the above code snippet, the class TradeValueCalculator depends on the implementation of the static methods like TradeUtils.calculateTax(..) and TradeUtils.calculateCommission(..). Any change in these static methods can lead to failures of unit tests of class TradeValueCalculator. Hence statics introduce unwanted coupling between classes, thereby violating the principle of easy unit-testability of POJOs. Avoid them, if you can, and use standard design idioms like composition-with-dependency-injection instead. And while using composition with service components, make sure they are powered by interfaces. Interfaces provide the right level of abstraction for multiple implementations and are much easier to mock while testing. Let us refactor the above snippet to compose using service components for calculating tax and commission :


class TradeValueCalculator {

  // .. to be dependency injected
  private ITaxCalculator taxCalculator;
  private ICommissionCalculator commissionCalculator;

  // ..
  // ..

  public BigDecimal calculateTradeValue(final Trade trade, ..) {
    // ..
    BigDecimal tax = taxCalculator.calculateTax(trade);
    BigDecimal commission = commissionCalculator.calculateCommission(trade);
    // .. other business logic to compute net value
  }
  // ..
  // ..
}

interface ITaxCalculator {
  BigDecimal calculateTax(..);
}

interface ICommissionCalculator {
  BigDecimal calculateCommission(..);
}



We can then have concrete instances of these service contracts and inject them into the POJO TradeValueCalculator :


class DefaultTaxCalculator implements ITaxCalculator {
  // ..
}

class DefaultCommissionCalculator implements ICommissionCalculator {
  // ..
}



Using standard IoC containers like Guice or Spring, we can inject concrete implementations into our POJO non-invasively through configuration code. In Guice we can define Modules that bind interfaces to concrete implementations and use Java 5 annotation to inject those bindings in appropriate places.



// define module to configure bindings
class TradeModule extends AbstractModule {

  @Override
  protected void configure() {
  bind(ITaxCalculator .class)
      .to(DefaultTaxCalculator .class)
      .in(Scopes.SINGLETON);

    bind(ICommissionCalculator .class)
      .to(DefaultCommissionCalculator .class)
      .in(Scopes.SINGLETON);
  }
}



and then inject ..


class TradeValueCalculator {

  // ..
  @Inject private ITaxCalculator taxCalculator;
  @Inject private ICommissionCalculator commissionCalculator;

  // ..
  // ..
}



How does this improve testability of our class TradeValueCalculator ?

Just replace the defined Module by another one for unit testing :


// define module to configure bindings
class TestTradeModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(ITaxCalculator .class)
      .to(MockTaxCalculator .class)
      .in(Scopes.SINGLETON);

    bind(ICommissionCalculator .class)
      .to(MockCommissionCalculator .class)
      .in(Scopes.SINGLETON);
  }
}



What we have done just now is mocked out the service interfaces for tax and commission calculation. And that too without a single line of code being changed in the actual class! TradeValueCalculator can now be unit-tested without having any dependency on other classes.

Extreme Encapsulation

I have come across many abuses of FluentInterfaces, where developers use chained method invocations involving multiple classes. Take this example from this Mock Objects paper, which discusses this same problem :

dog.getBody().getTail().wag();

The problem here is that the main class Dog is indirectly coupled with multiple classes, thereby violating the Law of Demeter and making it totally unsuitable for unit testing. The situation is typically called "The Train Wreck" and has been discussed extensively in the said paper. The takeway from this situation is to minimize coupling with neighbouring classes - couple only with the class directly associated with you. Think in terms of abstracting the behavior *only* with respect to the class with which you collaborate directly - leave implementation of the rest of the behavior to the latter.

Privates also need to be Unit-Tested

There is a school of thought which espouses the policy that *only* public api s need to be unit-tested. This is not true - I firmly believe that all your methods and behaviors need unit testing. Strive to achieve the maximum coverage of unit testing in your classes. Roy Osherove thinks that we may have to bend some of the rules of pure OOD to make our design implementations more testable e.g. by exposing or replacing private instances of objects using interfaces, injection patterns, public setters etc. Or by discouraging default sealing of classes allowing overriding in unit tests. Or by allowing singletons to be replaced in tests to break dependencies. I think, I agree to many of these policies.

Fortunately Java provides a useful access specifier that comes in handy here - the package private scope of access. Instead of making your implementation members *private*, make them *package private* and implement unit test classes in the same package. Doing this, you do not expose the private parts to the public, while allowing access to all unit test classes. Crazy Bob has more details on this. Another useful trick to this may be usage of AOP. As part of unit test classes, you can introduce additional getters through AOP to access the implementation artifacts of your class. This can be done through inter-type declarations, and the test classes can access all private data at gay abandon.

Look out for Instantiations

There are many cases where the class that is being unit tested needs to create / instantiate objects of the collaborating class. e.g.


class TradeController {

  // ..
  // ..

  public void doTrade(TradeDTO dto, ..) {
    Trade trade = new Trade(dto);
    // .. logic for trade
  }
  // ..
}



Increase the testability of the class TradeController by separating out all creation into appropriate factory methods. These methods can then be overridden in test cases to inject creation of Mock objects.


class TradeController {
  TradeDTO dto;

  // ..
  // ..

  public void doTrade() {
    Trade trade = createTrade(dto);
    // .. logic for trade
  }
  // ..

  protected Trade createTrade(TradeDTO dto) {
    return new Trade(dto);
  }
}



and create MockTrade in test cases ..


class TradeControllerTest extends TestCase {

  // ..

  public void testTradeController(..) {
    TradeController tc = new TradeController() {
      protected Trade createTrade(TradeDTO dto) {
        return new MockTrade(dto);
      }
    }
    tc.doTrade();
  }
}



The Factory Method pattern proves quite helpful in such circumstances. However, there are some design patterns like The Abstract Factory, which can potentially introduce unwanted coupling between classes, thereby making them difficult to unit-test. Most of the design patterns in GOF are built on composition - try implementing them using Interfaces in Java, so that they can be easily mocked out. Another difficult pattern is the Singleton - I usually employ the IoC container to manage and unit-test classes that collaborate with Singletons. Apart from static methods, which I have already mentioned above, static members are also problematic cases for unit testing. In many applicatiosn they are used for caching (e.g. ORMs) - hence an obvious problem child for unit testing.