On Mar 25, 2008, at 12:04 AM, Pat Maddox wrote: > On Mon, Mar 24, 2008 at 6:50 PM, Chuck Remes > <[EMAIL PROTECTED]> wrote: >> So I have a complex object that I need to construct. This complex >> object, at runtime, takes an object in its initializer. The >> initializer interrogates the object and creates several collaborative >> objects based upon values from that interrogation. >> >> The construction is complicated enough that it pretty much begs to be >> implemented via the Builder Pattern. >> >> My problem is that I don't know how to test this behavior regardless >> of whether the object handles its own construction or I create a >> separate Builder object to construct it for me. >> >> For example: >> >> class ComplexObjectBuilder >> def initialize >> @complex_object = ComplexObject.new >> end >> >> def create_foo(control, value) >> case control do >> when :a then @complex_object.foo = SpecialObject.new(value * 4) >> when :v then @complex_object.foo = OtherObject.new >> when :z then @complex_object.foo = YAObject.new >> end >> end >> >> def create_bar(control, value) >> # similar to above >> end >> >> def construct >> # some business rules to make sure the object is complete; use >> # defaults for fields that were not set via the interface >> return @complex_object >> end >> end >> >> @builder = ComplexObjectBuilder.new >> @builder.create_foo(params_object.accessor1, params_object.accessor2) >> @builder.create_bar(params_object.accessor3, params_object.accessor4) >> baz = @builder.construct >> >> How the heck do I test anything here? I do not see how I can >> validate >> the behavior of #create_foo or #create_bar without exposing >> @complex_object via a public interface. Those #create_* methods are >> purely for construction and do not return a value. Only #construct >> returns a value which should be the completed object >> >> Is there a transformation to consider to make this more testable? >> >> I'm hoping someone has tackled this before and can provide me some >> insight. Many thanks... >> >> cr > > Hey Chuck, > > I would toss whatever code you have and BDD it from scratch. > Shouldn't be that difficult...you can start off with stuff like > > describe ComplexObjectBuilder, " when foo is built with :a" do > before(:each) do > builder = ComplexObjectBuilder.new > builder.create_foo :a, 3 > @built = builder.construct > end > it "should create a special object" do > @built.foo.should be_a(SpecialObject) > end > > it "should quadruple the value passed to the special object" do > @built.foo.some_val.should == 12 > end > end >
Pat, thanks for your response. I have question regarding your suggestion. In the first "it" you are asserting that @built.foo should be an object. The @built instance variable is the ComplexObject and not the ComplexObjectBuilder. Shouldn't we be testing the behavior of the builder and not the ComplexObject the builder produces? Another way, shouldn't I put the ComplexObject assertions into its own set of specs? It just seems like we're mixing the behavior of two objects here: ComplexObjectBuilder and ComplexObject. Perhaps that is okay since they are so tightly coupled. In a sense the ComplexObjectBuilder is just a fancy constructor for the other object; it only gets refactored out to its own object because it has so many parts/steps. ?? cr _______________________________________________ rspec-users mailing list [email protected] http://rubyforge.org/mailman/listinfo/rspec-users
