Using the Builder pattern with AtUnit

7 views
Skip to first unread message

Gili

unread,
Oct 28, 2008, 2:31:13 PM10/28/08
to atunit
Hi,

I'm trying to use the Builder design pattern with AtUnit. Typically
AtUnit expects:

@Mock UriInfo uriInfo;

it injects it and expects me to configure the instance in my test
methods. The Builder design pattern, on the other hand, expects me to
configure the builder and returns a *new* instance. Is it possible to
somehow use the Builder pattern and push the result into the active
Injector? Or perhaps you have a cleaner approach in mind?

I used to isolate duplicate mock-configuration code in its own methods
but these are starting to get out of hand, needing multiple calls
against the same mock object. The Builder pattern is nicer in that all
the methods are encapsulated within the same class. I could pass in an
existing instance and as it to configure it but then it's not really a
Builder anymore :P

Gili

Logan Johnson

unread,
Oct 28, 2008, 4:22:08 PM10/28/08
to atu...@googlegroups.com
Well, you could do something like this:

public static class StringHolder {
        @Inject String held;
    }

public class BuilderTest implements Module {

    @Inject @Unit Provider<StringHolder> subject;
    @Inject StringBuilder builder;

    public void configure(Binder b) {
        final StringBuilder builder = new StringBuilder();
        builder.append("in configure | ");

        b.bind(StringBuilder.class).toInstance(builder);
        b.bind(String.class).toProvider(new Provider<String>() {
            public String get() {
                return builder.toString();
            }
        });
    }

    @Test
    public void testMethod() {
        builder.append("in test method");
        StringHolder sh = subject.get();
        System.out.println(sh.held);  // prints "in configure | in test method"
    }
}

Substitute your mock's interface for String and your mock builder for StringBuilder.

That's pretty onerous unless your builders all implement an interface that you can use to make a generic provider class.  And the subject.get() is a little bit annoying.


--Logan

Gili Tzabari

unread,
Oct 28, 2008, 4:44:23 PM10/28/08
to atu...@googlegroups.com

Unfortunately the Builder is passed different arguments depending
on the test so this wouldn't work. What I did instead was:

1) Rename the Builder to Facade
2) Create a new UriInfo in configure() and bind().toInstance() for it.
3) Create a new Facade in configure() that takes the UriInfo as argument
in its constructor. bind() that Facade.
4) @Inject the Facade into the test class and force tests to use it
instead of the UriInfo (the latter is not exposed at all in the test class).

The resulting code is very clean and reusable :)

Gili

Logan Johnson

unread,
Oct 28, 2008, 5:24:23 PM10/28/08
to atu...@googlegroups.com
Notice that in my test method, I am able to pass arguments to the builder which are used when its build() method is called to create the test subject.  IOW, you can pass different arguments depending on the test.

That said, your solution sounds nice.  Glad you got it worked out.

--Logan
Reply all
Reply to author
Forward
0 new messages