Mark Needham

Thoughts on Software Development

Java: Faking a closure with a factory to create a domain object

with 10 comments

Recently we wanted to create a domain object which needed to have an external dependency in order to do a calculation and we wanted to be able to stub out that dependency in our tests.

Originally we were just new’ing up the dependency inside the domain class but that makes it impossible to control it’s value in a test.

Equally it didn’t seem like we should be passing that dependency into the constructor of the domain object since it’s not a piece of state which defines the object, just something that it uses.

We ended up with something similar to the following code where we have our domain object as an inner class:

public class FooFactory {
    private final RandomService randomService;
 
    public FooFactory(RandomService randomService) {
        this.randomService = randomService;
    }
 
    public Foo createFoo(String bar, int baz) {
        return new Foo(bar, baz);
    }
 
    class Foo {
        private String bar;
        private int baz;
 
        public Foo(String bar, int baz) {
            this.bar = bar;
            this.baz = baz;
        }
 
        public int awesomeStuff() {
            int random = randomService.random(bar, baz);
            return random * 3;
        }
    }
}

A test on that code could then read like this:

public class FooFactoryTest {
    @Test
    public void createsAFoo() {
        RandomService randomService = mock(RandomService.class);
        when(randomService.random("bar", 12)).thenReturn(13);
 
        FooFactory.Foo foo = new FooFactory(randomService).createFoo("bar", 12);
        assertThat(foo.awesomeStuff(), equalTo(39));
    }
}

It’s a bit of a verbose way of getting around the problem but it seems to work reasonably well.

Be Sociable, Share!

Written by Mark Needham

February 26th, 2012 at 12:09 am

Posted in Java

Tagged with

  • Alexander Yap

    Given that the RandomService can be created elsewhere and passed to the factory, it means that it can be created without depending on any state within the Foo class. Also, you were just new’ing it within Foo in the past,  so I guess it doesn’t depend on anything external to Foo either. 

    Therefore, why not just create it as Foo’s instance variable (or in its constructor)? 

    public class Foo {
    private RandomService randomService = new RandomService();
    …}

    Then in your test, just override it with a mock.

    Field field = Foo.class.getDeclaredField(“randomService”);
    field.setAccessible(true);
    field.set(fooInstance, mockRandomService);

    This way, you don’t pollute Foo’s client with knowledge of external services it doesn’t need to know about.

  • http://www.markhneedham.com/blog Mark Needham

    Good point about Foo’s client having knowledge of external services..

    We actually don’t really see that problem because the client which creates a Foo is injected with a ‘FooFactory’ so it never actually sees the ‘RandomService’ anyway. 

    But yeh the way you describe seems reasonable as well, just maybe a bit more fiddly.

  • http://blog.thecodewhisperer.com J. B. Rainsberger

    Since only awesomeStuff() uses RandomService, we have to ask whether it should simply be a parameter of awesomeStuff(). Only when other methods on the class need awesomeStuff() would I promote RandomService to a collaborator (meaning constructor parameter).

    I’m afraid I don’t understand this statement: “Equally it didn’t seem like we should be passing that dependency into the constructor of the domain object since it’s not a piece of state which defines the object, just something that it uses.” Wouldn’t that be true of all services? Maybe this domain object shouldn’t hardcode its dependency on the implementation of a service. Apply the usual solution: invert the dependency, and make awesomeStuff() demand an implementation of RandomService.

    Hm: two different first-principle approaches leading to the same solution. I’m convinced. :)

  • http://www.markhneedham.com/blog Mark Needham

    @jbrainsberger:disqus In our actual code there are 3 other parameters which are passed into ‘awesomeStuff’, 2 of which are used by ‘RandomService’ and one which is used elsewhere.

    It didn’t seem that the API of the method read as nicely if we passed ‘RandomService’ in as a method parameter – is that a valid reason for not passing it in? 

  • http://blog.thecodewhisperer.com J. B. Rainsberger

    It’s getting difficult to answer without looking at the specific example, but I’ll try.

    What would happen if you told the caller to pass those two parameters directly to RandomService before passing the RandomService to awesomeStuff()? Have you tried that? Maybe Foo doesn’t need to depend on those two parameters at all.

    What I’ve seen so far points me strongly in the direction of inverting the dependency in a way similar to this. That usually makes me uncomfortable, and it’s usually still right. :)

  • Sander

    The title should have read: “Domain objects as nested class of factory”. This is not about faking anything and it’s “dangerous”. Each instance of that nested class can only exist within an instance of the outer class. So what happens if the factory gets destroyed? Not to mention: you want to use that FooFactory.Foo everywhere you mention the domain object? Everywhere you use the domain object you’d have to have notion of the factory as well. 

    All you have to do is call one setter on the Foo object in the factory and set that service as a property of the object. Is it a part of the state? Can a car drive without an engine? Even though the car “just uses” the engine it’s still a part of the car. 

  • Brian

    interface RandomService {
      int random(String bar, int baz);
    }

    class RandomServiceImpl {
      public static int random(String bar, int baz) {…}
    }

    class Foo implements RandomService {
      int random(String bar, int baz) {
        return RandomServiceImpl.random(bar, baz)
      }
    }

    To test just override Foo.random. Seems simple enough unless I am missing something from the given example.

  • http://blog.thecodewhisperer.com J. B. Rainsberger

    Subclass To Test works just fine here, and I use it frequently as an intermediate step towards Replace Inheritance with Delegation.

  • http://code.google.com/p/jmockit Rogerio

    If you were originally new’ing up RandomService inside the domain class, then maybe that’s the best design. More often than not, business service interfaces have a single implementation which doesn’t need to be selected through external configuration (DI), so it makes perfect sense to “hardcode” it (simplest thing that works first – you can always introduce a factory, DI, etc. later if needed).

    To unit test the domain class, you can still mock a new’ed RandomService. For example, as shown in the following test:

        public void testAwesomeStuff() {
            new Expectations() {
                RandomService mockedService;

                {
                    mockedService.random(“bar”, 12);
                    result = 13;
                }
            };

            Foo foo = new Foo(“bar”, 12);
            assertThat(foo.awesomeStuff(), equalTo(39));
        }

    Succint, and with no “FooFactory” needed.

  • http://mozartmb.wordpress.com/ Mozart Brocchini

    Hmm, several good points already mentioned in other comments.
    I’ll just throw a couple of ideas here since the discussion have been informative and educative so far.

    It soundslike the problem you’re reporting could benefit from using mixins see http://en.wikipedia.org/wiki/Mixin.

    However since Java lacks the mixin feature, I think it would be OK to use a composition through constructor DI because you’re not using the anemic domain model.

    Now, another way to solve this is to use another structural pattern other than factory.
    You could use the builder pattern(factory methods) like so: 

    public class Foo {
        private final RandomService randomService;
        private Foo(RandomService randomService, String bar, int baz) { 
          this.bar = bar;       this.baz = baz;
          this.randomService = randomService 
       } 
       public static Foo build(String bar, int baz) {
         if (randomService==null) {   
            return new Foo(new RandomService(), bar, baz);      
         }  
        return new Foo(this.randomService, bar, baz);   
     }   
     public static Foo forRandomService(RandomService randomService) {   
        return new Foo(nrandomService, null, null);    
     } 
       ...
    }    
      /*   
     // Foo client code using default RandomService implementation : 
        Foo foo = Foo.build(bar, baz);    
      // Test code : 
        Foo foo = Foo.forRandomService(mockService).build(bar, baz);
     */