BDD on Creatine
Thursday, March 12, 2009 9:46:14 AM (Mountain Standard Time, UTC-07:00)
In an attempt to further understand BDD, I chose to revise the code from my previous post after receiving some amazing advice from two people I regard highly (Scott & JP). I should state that this is my interpretation of that advice. This may or may not be the direction they were trying to guide me towards.
12 public class when_prompted_to_save_changes_to_the_project : concerns_for<SaveChangesView>
13 {
14 context c = () => { presenter = an<ISaveChangesPresenter>(); };
15
16 after_the_sut_has_been_created after = () =>
17 {
18 save_changes_window = sut;
19 save_changes_window.attach_to(presenter);
20 };
21
22 protected static ISaveChangesPresenter presenter;
23 protected static SaveChangesView save_changes_window;
24 }
25
26 public class when_the_save_button_is_pressed : when_prompted_to_save_changes_to_the_project
27 {
28 it should_save_the_current_project = () => presenter.was_told_to(x => x.save());
29
30 because b = () => save_changes_window.save_button.control_is(x => x.OnClick(new EventArgs()));
31 }
32
33 public class when_the_cancel_button_is_pressed : when_prompted_to_save_changes_to_the_project
34 {
35 it should_not_continue_processing_the_previous_action = () => presenter.was_told_to(x => x.cancel());
36
37 because b = () => save_changes_window.cancel_button.control_is(x => x.OnClick(new EventArgs()));
38 }
39
40 public class when_the_do_not_save_button_is_pressed : when_prompted_to_save_changes_to_the_project
41 {
42 it should_not_save_the_project = () => presenter.was_told_to(x => x.dont_save());
43
44 because b = () => save_changes_window.do_not_save_button.control_is(x => x.OnClick(new EventArgs()));
45 }
I hope this is slightly more soluble, then my previous post.
Ooops...
Monday, August 04, 2008 9:54:26 AM (Mountain Standard Time, UTC-07:00)
Mike left a comment on my last post on Windows Forms Databinding asking:
What do the tests look like?
On the ComboBox binding, why aren't you using adding the binding through DataBinding.Add? With the way you have it now if you change the value the combobox is bound too it doesn't get pushed back to the screen.
Well Mr. Mike, on the view implementation there were no tests... *hang my head in shame* Yup, we went at it trying to understand how Windows Forms Data bindings works, but if we had gone at it test first, we would have found that leveraging the built-in data bindings are not very testable. It requires having a BindingContext setup, and in some cases the controls have to actually be displayed for the bindings to actually kick in. Second, if we had gone test first, we would have noticed the issue the Mike brought up in regards to the ComboBox.
Feeling a little guilty about publishing code that wasn't well thought out, I decided to go at it again, with a test first approach. The test started off very high level. I knew the API that I wanted to work with, in this case a fluent interface for defining a binding to a control. The end result was quite different..
[Concern(typeof (Create))]
public class when_binding_a_property_from_an_object_to_a_combo_box : context_spec {
[Test]
public void should_initialize_the_combo_box_with_the_current_value_of_the_property() {
combo_box.SelectedItem.should_be_equal_to(baby_girl);
}
protected override void under_these_conditions() {
combo_box = new ComboBox();
thing_to_bind_to = Dependency<IAnInterface>();
baby_girl = Dependency<IAnInterface>();
baby_boy = Dependency<IAnInterface>();
combo_box.Items.Add(baby_boy);
combo_box.Items.Add(baby_girl);
thing_to_bind_to
.setup_result_for(t => t.Child)
.Return(baby_girl);
}
protected override void because_of() {
Create
.BindingFor(thing_to_bind_to)
.BindToProperty(t => t.Child)
.BoundToControl(combo_box);
}
private ComboBox combo_box;
private IAnInterface thing_to_bind_to;
private IAnInterface baby_girl;
private IAnInterface baby_boy;
}
The end result doesn't leverage the Windows Forms databindings at all. It registers event handlers for events on the controls.
public class ComboBoxPropertyBinding<TypeToBindTo, PropertyType> : IPropertyBinding<PropertyType> {
private readonly IPropertyBinder<TypeToBindTo, PropertyType> binder;
public ComboBoxPropertyBinding(ComboBox control, IPropertyBinder<TypeToBindTo, PropertyType> binder) {
this.binder = binder;
control.SelectedItem = binder.CurrentValue();
control.SelectedIndexChanged +=
delegate { binder.ChangeValueOfPropertyTo(control.SelectedItem.ConvertedTo<PropertyType>()); };
}
public PropertyType CurrentValue() {
return binder.CurrentValue();
}
}
If you're interested in the rest of the source code download the source here. The moral of the story... Don't become complacent and take off your TDD hat, prematurely. In most cases it can, and should be, tested. Your design will probably come out much cleaner then going at the problem head on without tests to back you up. Not only that, but tests also give you extension points for making changes, and dealing with different contexts you probably wouldn't have thought of right off the bat.